<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Brian Kung</title>
    <subtitle>⅔ non-programming.</subtitle>
    <link rel="self" type="application/atom+xml" href="https://briankung.dev/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://briankung.dev"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-02-19T05:39:06+00:00</updated>
    <id>https://briankung.dev/atom.xml</id>
    <entry xml:lang="en">
        <title>On AI assisted coding</title>
        <published>2026-02-19T05:39:06+00:00</published>
        <updated>2026-02-19T05:39:06+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2026/02/19/on-ai-assisted-coding/"/>
        <id>https://briankung.dev/2026/02/19/on-ai-assisted-coding/</id>
        
        <content type="html" xml:base="https://briankung.dev/2026/02/19/on-ai-assisted-coding/">&lt;p&gt;A lot has happened in software engineering since my last post. I&#x27;ve had a draft post called &quot;LLMs are crazy good&quot; for a while now, but suffice to say that LLMs have gotten even better at coding since then, to the degree that they are now essentially my preferred way to edit the text files that we call code.&lt;&#x2F;p&gt;
&lt;p&gt;Also, it feels silly to have to write this, but every word on this blog has been and always will be written 100% by a human, except for code. I would say &quot;artisanally hand-crafted,&quot; but some days it&#x27;s more like slapped together with a stapler and chucked out the window. This is one of those days, to be honest.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;llms-are-an-abstraction-layer-comparable-to-compilers&quot;&gt;LLMs are an abstraction layer comparable to compilers&lt;&#x2F;h2&gt;
&lt;p&gt;The basic idea is that LLMs allow us to move up another abstraction level, similar to how compilers did in the 1950s (thank you, Admiral Grace Hopper). Were a lot of people concerned about the output of compilers back then? They sure were. Are they now? Only compiler engineers. Are a lot of people concerned about the output of LLMs today? They sure are. Will they be concerned about the output of LLMs tomorrow? I honestly don&#x27;t think so.&lt;&#x2F;p&gt;
&lt;p&gt;I think as we learn to use LLMs for code generation, we will find out more ways to make the output deterministic &lt;em&gt;in the ways that we care about&lt;&#x2F;em&gt;. Do I care whether an API is written in Ruby or Rust? Do I care whether a website was written with htmx or erb? No, I don&#x27;t.&lt;&#x2F;p&gt;
&lt;p&gt;Someone wrote a blog post that probably thought a lot more about the analogy which you should definitely read: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;alperenkeles.com&#x2F;posts&#x2F;llms-could-be-but-shouldnt-be-compilers&#x2F;&quot;&gt;https:&#x2F;&#x2F;alperenkeles.com&#x2F;posts&#x2F;llms-could-be-but-shouldnt-be-compilers&#x2F;&lt;&#x2F;a&gt; My one comment on the contents of the post would be that 1) compilers aren&#x27;t entirely deterministic, either, and 2) we can and &lt;em&gt;will&lt;&#x2F;em&gt; find ways to increase the reliability of LLM output.&lt;&#x2F;p&gt;
&lt;p&gt;Side story: My dad told me a story about picking flooring for a home remodeling project. He went to the flooring store with my mom and they were agonizing over their choices. The sales rep gave them a few options and then, after witnessing the agony, shrugged, and said &quot;it&#x27;s just money&quot; and laughed. In our case, the sales rep is Anthropic and they&#x27;re saying &quot;it&#x27;s just tokens.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;The point is, you can now waste tokens to talk through the specification with your LLM agent. And speaking of specifications...&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-specification-is-the-application-now&quot;&gt;The specification &lt;em&gt;is&lt;&#x2F;em&gt; the application now&lt;&#x2F;h2&gt;
&lt;p&gt;These days, the specification is the application, now, or at least more so than before. LLMs do much better when there&#x27;s some sort of deterministic output they can test their code against. For example, JustHTML passes 100% of the html5lib test suite and was entirely vibecoded: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;friendlybit.com&#x2F;python&#x2F;writing-justhtml-with-coding-agents&#x2F;&quot;&gt;https:&#x2F;&#x2F;friendlybit.com&#x2F;python&#x2F;writing-justhtml-with-coding-agents&#x2F;&lt;&#x2F;a&gt; And they were able to do it because &lt;em&gt;there is a test suite in the first place.&lt;&#x2F;em&gt; Meanwhile, Anthropic had Claude Opus 4.6 build a working C compiler that can compile the Linux kernel. The trick was to have a reference compiler and a great harness for writing a clean room implementation.&lt;&#x2F;p&gt;
&lt;p&gt;These, on the spectrum of &quot;formally specified&quot; on one end to &quot;bro, I have an idea for an app that&#x27;s like Strava plus Hinge&quot; are definitely much closer to &quot;formally specified.&quot; There&#x27;s a clear feedback loop that tells the LLM objectively whether it&#x27;s headed in the right direction, and a test suite that lets it iterate toward the goal. There&#x27;s actually a library that is just a list of specifications of the behavior. If you can find that library for me, I would appreciate it.&lt;&#x2F;p&gt;
&lt;p&gt;I feel like &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;cucumber.io&#x2F;&quot;&gt;Cucumber&lt;&#x2F;a&gt; needs to make a comeback, but this time powered by LLMs trying to playtest your website with Playwright:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;gherkin&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;When &lt;&#x2F;span&gt;&lt;span&gt;logged in as a User I should be able to personally send Anthropic&amp;#39;s stock price to the moon 🚀&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So how does this affect software development? We&#x27;re going to be much more in the business of specifying behaviors rather than writing fiddly text keywords to match syntactical rules. I think it&#x27;s inevitable. It&#x27;s not just a matter of cost and efficiency - it&#x27;s just a better way to code. But it is all of those things as well.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;llms-are-fpgas-and-runtimes-are-asics&quot;&gt;LLMs are FPGAs and runtimes are ASICs&lt;&#x2F;h2&gt;
&lt;p&gt;FPGAs, or Field Programmable Gate Arrays, are hardware based logic boards that can be programmed to represent different logical circuits. When TSMC tapes out a chip, the design is always going to be a certain way. FPGAs let you program the physical design to your specification and it will behave as if it was a hardware circuit board design, albeit slower and less capable than the real thing.&lt;&#x2F;p&gt;
&lt;p&gt;ASICs, on the other hand, are Application Specific Integrated Circuits, and they are fully specified circuit boards that achieve a single purpose. These are often desirable because they&#x27;re cheaper to produce and perform much quicker than FPGAs or more general purpose designs.&lt;&#x2F;p&gt;
&lt;p&gt;In our analogy, LLMs are FPGAs. You can load an LLM up and tell it to pretend to be a command line terminal and it will respond as if you were &lt;code&gt;ssh&lt;&#x2F;code&gt;&#x27;ing into a remote computer somewhere. They are the ultimate general purpose, if somewhat chaotic, computing tools. &lt;em&gt;However&lt;&#x2F;em&gt;. They can be used to encode processes into code. And code is far less chaotic than an LLM is, and that is a benefit when you want to &lt;em&gt;use&lt;&#x2F;em&gt; a tool instead of learn how to use the latest model. It&#x27;s also typically far less resource intensive than waiting for inference from an LLM. If you&#x27;re using the same runtime and the same code, you should more often than not get the same result.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;coding-feels-dead&quot;&gt;Coding feels dead&lt;&#x2F;h2&gt;
&lt;p&gt;I follow coding subreddits like Rust and Ruby and I have to say - it all feels dead now. There are fewer high quality posts, and the excitement is all in LLM submissions that, for better or for worse, have a much higher bar to meet before readers consider them remarkable. The magic feels simultaneously over and underwhelming. Software engineering used to feel like a delicate ballet of computers, orchestrated by a careful choreographers.&lt;&#x2F;p&gt;
&lt;p&gt;Now you can get world class software engineering knowledge at the touch of a button, if you ask the right questions. It&#x27;s great, but it&#x27;s also a kind of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;simonwillison.net&#x2F;2026&#x2F;Feb&#x2F;15&#x2F;deep-blue&#x2F;&quot;&gt;Deep Blue&lt;&#x2F;a&gt;, a melancholy that Kasparov and later Lee Sedol must have faced when they were the first humans to be thoroughly defeated by computers in the games of Chess and Go, respectively.&lt;&#x2F;p&gt;
&lt;p&gt;I think that, despite the melancholy, we will adapt like the board gaming communities have. The game is still about people, but we will use AI to enhance our own training and our own capabilities. The melancholy is that we&#x27;ve built something that so far outpaces our capacity that we are, in a way, puppets of the machines rather than the operators.&lt;&#x2F;p&gt;
&lt;p&gt;In truth, the entire internet feels dead now, but this isn&#x27;t a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Dead_Internet_theory&quot;&gt;new theory&lt;&#x2F;a&gt;. It&#x27;s just that the internet is now aggressively dead, like a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=mWEhfF27O0c&quot;&gt;28 Days Later&lt;&#x2F;a&gt; kind of dead rather than an Abraham Lincoln sort of dead.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;on-trusting-trust&quot;&gt;On trusting trust&lt;&#x2F;h2&gt;
&lt;p&gt;Another compiler analogy, but the seminal paper &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.cs.cmu.edu&#x2F;~rdriley&#x2F;487&#x2F;papers&#x2F;Thompson_1984_ReflectionsonTrustingTrust.pdf&quot;&gt;&quot;Reflections on Trusting Trust&quot;&lt;&#x2F;a&gt; explores how a backdoor in a compiler could lead to almost completely undetectable security vulnerabilities.&lt;&#x2F;p&gt;
&lt;p&gt;In LLMS, we&#x27;re already seeing OpenAI talk about ads, but the problem of trusting trust is actually even worse than the problem in compilers, since compilers are actually somewhat transparent compared to LLM models. So much of the model training process is obfuscated, from the data sources (like Facebook &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;arstechnica.com&#x2F;tech-policy&#x2F;2025&#x2F;07&#x2F;meta-pirated-and-seeded-porn-for-years-to-train-ai-lawsuit-says&#x2F;&quot;&gt;infamously claiming&lt;&#x2F;a&gt; that its seeding 81.7TB of porn was for &quot;personal use&quot;) to the training harnesses, to the processes, and at the end you get a massive binary blob of &lt;em&gt;statistics&lt;&#x2F;em&gt; somehow representing the sum knowledge of humanity. A hypercube of billions of parameters for the pachinko ball of your piddly prompt to bounce through until you get an answer you&#x27;re satisfied with.&lt;&#x2F;p&gt;
&lt;p&gt;No one but the most well funded AI labs can introspect these things. And the actors on the web are quickly adapting to poison the wells the LLMs came from, whether from careless neglect and AI slop, or outright malice and pushing narratives to their own purposes. And finally, capital must always have its say, and so we have the ads injected into every prompt. I wouldn&#x27;t be surprised if it was eventually a service to have ads injected into the training data itself, to permanently bias LLMs, though I have my doubts as to the economics of that business model.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ethics&quot;&gt;Ethics&lt;&#x2F;h2&gt;
&lt;p&gt;If you&#x27;re coming from a Western perspective of intellectual property (as opposed to, say, a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.bunniestudios.com&#x2F;blog&#x2F;the-12-gongkai-phone&#x2F;&quot;&gt;gongkai&lt;&#x2F;a&gt; perspective), then AI is inherently unethical. It&#x27;s based on intellectual property laundering that washes away ownership through statistics. Image generation models all know what they&#x27;re &lt;em&gt;not&lt;&#x2F;em&gt; supposed to generate when you ask them for Avengers, Disney characters, Ghibli characters, or Pokemon. They absolutely can and will generate faithful recreations of all of the above, however.&lt;&#x2F;p&gt;
&lt;p&gt;LLMs are also yet another source of emissions that contribute to climate change, and use precious resources. In the most egregious examples, they directly compromise vulnerable populations with their emissions when the electricity grid can&#x27;t meet the AI datacenter demands.&lt;&#x2F;p&gt;
&lt;p&gt;And yet, this technology won&#x27;t go away. We can spurn it, we can denounce it, but we must in some ways engage with it.&lt;&#x2F;p&gt;
&lt;p&gt;The ethics of AI are not that much different than deciding to take an airplane somewhere, drive your car, or remodel your house. Everything we do, especially what we do out of convenience, creates waste. All waste has externalities and all externalities are paid for by the common folk, ultimately.&lt;&#x2F;p&gt;
&lt;p&gt;The problem is upstream of &quot;do I use LLMs today?&quot; and it&#x27;s upstream of &quot;do I drive a car to work today?&quot; In my opinion, we need to do our individual parts to reduce waste and the effect on the global good that is the health of our globe, but we must also balance that against the need to hold society and particularly corporations accountable for their share of the tragedy of the commons.&lt;&#x2F;p&gt;
&lt;p&gt;We should have technology that we can depend on as a public good, efficient infrastructure that sips resources, equitable access to the rewards that come from progress. That, unfortunately, is something that no prompt can solve. Only we can hold other humans accountable, and only we can share the fruits of our labors with others.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Only software engineering can save us from vibe coding.</title>
        <published>2025-04-18T03:17:15+00:00</published>
        <updated>2025-04-18T03:17:15+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2025/04/18/only-software-engineering-can-save-us-from-vibe-coding/"/>
        <id>https://briankung.dev/2025/04/18/only-software-engineering-can-save-us-from-vibe-coding/</id>
        
        <content type="html" xml:base="https://briankung.dev/2025/04/18/only-software-engineering-can-save-us-from-vibe-coding/">&lt;p&gt;I saw a &quot;stop learning to code, vibe coding is here now&quot; post and I had to write a response: While it&#x27;s true that AI has commoditized the act of stringing characters together into code, it hasn&#x27;t commoditized software engineering. In fact, it&#x27;s made software engineering more important and more accessible.&lt;&#x2F;p&gt;
&lt;p&gt;The difference between coding and software engineering is that software engineers know that every line of code is a liability. Consider this quote (purportedly) by Bill Gates:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Measuring programming progress by lines of code is like measuring aircraft building progress by weight.”&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Code is a liability for the same reason that excess weight is a liability for aircraft. Code needs to be maintained, and in order to be maintained, it needs to be understood. It is also a liability because, like any sharp tool, it can cause damage when executing in the wrong context. Code inherently runs against its own purposes because code is intended to solve a problem, but it creates its own problems by dint of existing.&lt;&#x2F;p&gt;
&lt;p&gt;So I think of the maintainable use, modification, and execution of code as software engineering. What does that mean?&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Fast, meaningful tests&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Observability&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Documentation&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Reproducibility&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Can AI do these things? Well, it can certainly help. Will it if you don&#x27;t steer it towards them? No, it won&#x27;t. But, crucially, if you do have these elements, it is a flywheel that safely accelerates any modification to your system, whether it&#x27;s coming from a user or from an LLM.&lt;&#x2F;p&gt;
&lt;p&gt;So please, if you only want to learn vibe coding, learn software engineering next. I promise the vibes will be immaculate when your test suite is green.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Tiny overly excited explainer about vector search</title>
        <published>2024-06-11T22:56:51+00:00</published>
        <updated>2024-06-11T22:56:51+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2024/06/11/tiny-overly-excited-explainer-about-vector-search/"/>
        <id>https://briankung.dev/2024/06/11/tiny-overly-excited-explainer-about-vector-search/</id>
        
        <content type="html" xml:base="https://briankung.dev/2024/06/11/tiny-overly-excited-explainer-about-vector-search/">&lt;p&gt;Random thing that I got excited about this morning because I wanted to add really nice search to my personal journal: vector embeddings.&lt;&#x2F;p&gt;
&lt;p&gt;Imagine a 3D Cartesian space, and in it there are words at various (x, y, z) points. Similar words are placed in similar locations. In this space, &quot;king&quot; and &quot;queen&quot; would be close to each other, whereas &quot;beggar&quot; would be far away. This is essentially what a &quot;vector embedding&quot; is, except that vector embeddings typically have a much higher dimensionality than 3D space.&lt;&#x2F;p&gt;
&lt;p&gt;For an example of a dimension, take the relationship between &quot;hot&quot; and &quot;cold.&quot; You might track that as a dimension to judge a word by. How about social vs antisocial? Or fast vs slow? If you rated each word on hundreds of such dimensions, you&#x27;d have a single vector in a high dimensional space:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;&#x2F;&#x2F; vector embedding for the word &amp;quot;ice&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;  &#x2F;&#x2F; hotness&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;  0.0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;  &#x2F;&#x2F; coldness&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;  1.0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;  &#x2F;&#x2F; social&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;  0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;  &#x2F;&#x2F; antisocial&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;  0.3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;  &#x2F;&#x2F; fast&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;  0.1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;  &#x2F;&#x2F; slow&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;  0.5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;&#x2F;&#x2F; Without comments:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;0.0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 1.0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 0.3&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 0.1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 0.5&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That vector space is technically a 6-dimensional hypercube, but it&#x27;s easier to visualize vector embeddings as being 3-dimensional.&lt;&#x2F;p&gt;
&lt;p&gt;The placement of words within the hypercube is done via arcane magic. In fact, the dimensions don&#x27;t really correlate to anything we could solidly name, unlike my example, and the &quot;words&quot; are actually fragments of words, text, or even bytes - they&#x27;re certainly not complete words. That&#x27;s why these neural networks understand that &quot;quick&quot; and &quot;quickly&quot; are similar.&lt;&#x2F;p&gt;
&lt;p&gt;Regardless, the end result is that you can take some text, run it through a neural network, and get the position of that text within the hypercube. Then you can see if there&#x27;s anything nearby that has the same semantic meaning. That way, when you search &quot;monarch man,&quot; the embeddings will return &quot;king&quot; instead of failing like traditional full-text search, which would require you to search &quot;k,&quot; &quot;ki,&quot; &quot;kin,&quot; or &quot;king.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;Creating the neural networks takes a lot of computing power, but once they&#x27;re done, you can download them for your own use in order to 1) convert words or phrases into positions in the hypercube, and 2) search the space for nearby entries instead of searching text for exact matches.&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, it&#x27;d be a huge improvement to search on my personal daily journal, so I would like to get it working. Someday, maybe.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Tests are an observability concern</title>
        <published>2024-02-07T17:04:24+00:00</published>
        <updated>2024-02-07T17:04:24+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2024/02/07/tests-are-an-observability-concern/"/>
        <id>https://briankung.dev/2024/02/07/tests-are-an-observability-concern/</id>
        
        <content type="html" xml:base="https://briankung.dev/2024/02/07/tests-are-an-observability-concern/">&lt;p&gt;The first thing I do when I encounter a strange code base is run the test suite. I do this because I can get an idea of:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;the exact use cases that the developers envisioned&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;the actual usability of the APIs&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;the overall health (read: test coverage) of the project&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;and get an idea of how development is done&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I&#x27;ve heard a lot about the benefits of test suites, even in the context of articles that are against TDD (test-driven development). For instance:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;They&#x27;re for regression testing&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;They inform the design of the software&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;They are a way of organizing the work into small chunks&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;And conversely, the negatives:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;They are code, and code is a liability&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;They are slow to write and maintain or refactor&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;You need to know what you are doing in order to write a test&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I&#x27;m not here to argue with any of these points, and I think different points are valid for different people and different situations. What I am interested in exploring is the idea that tests are a part of your code&#x27;s observability stack:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Observability is a system property that defines the degree to which the system can generate actionable insights. It allows users to understand a system’s state from these external outputs and take (corrective) action.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;glossary.cncf.io&#x2F;observability&#x2F;&quot;&gt;Observability | Cloud Native Glossary&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Tests are simple red&#x2F;green line-item indicators for the functionality of your system. In this case, the &quot;system&quot; is your code and the &quot;user&quot; is the developer. When a test fails, it is an &quot;actionable insight&quot; allowing the user to understand the code&#x27;s state and take action (you could also argue that testing the public interfaces of code makes it an &quot;external&quot; output).&lt;&#x2F;p&gt;
&lt;p&gt;A system that simply performs its function with no affordances for observability is a black box that doesn&#x27;t lend itself to change. Without indicators of what it&#x27;s doing or how it functions, it&#x27;s nearly impossible to have any confidence in its performance or methodology.&lt;&#x2F;p&gt;
&lt;p&gt;Imagine running &lt;code&gt;.&#x2F;bin&#x2F;server&lt;&#x2F;code&gt; and being greeted with a blank screen. Is it running? What port is it listening on? What does it do? What is its API like?&lt;&#x2F;p&gt;
&lt;p&gt;A code base without a test suite is like a server with no logs. As someone tasked with the maintenance of the code base, developers are higher order &quot;operators&quot; of sorts, where the output of the operation is a functioning program.&lt;&#x2F;p&gt;
&lt;p&gt;Ultimately, this post is less about the importance of tests and more about the importance of observability. Being able to see into our systems is crucial in order to maintain them, and tests are a front-line mechanism for deriving &lt;em&gt;actionable insights&lt;&#x2F;em&gt; from the state of your code.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;To me, &lt;em&gt;legacy code&lt;&#x2F;em&gt; is simply code without tests. […] Code without tests is bad code. It doesn&#x27;t matter how well written it is; it doesn&#x27;t matter how pretty or object-oriented or well-encapsulated it is. With tests, we can change the behavior of our code quickly and verifiably. Without them, we really don&#x27;t know if our code is getting better or worse.&lt;&#x2F;p&gt;
&lt;p&gt;Michael Feathers, Working Effectively with Legacy Code&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Observability at any level may not be a priority for a two-person startup, but it is guaranteed to become a critical concern the more successful a project becomes. The more observable your system is, the easier it is to fix or change.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ll close out with an analogy that I&#x27;ve been toying with: a test suite is basically the nervous system of code. Making a change that triggers a regression in the unit test is like stretching in the morning and rediscovering that yesterday was leg day. Your nerves tell you swiftly where the affected area is, and you can move to correct the error. Without your nerves to tell you where and what is happening, you won&#x27;t be able to react appropriately to the state of your health. The same goes with a good unit test. Without tests, your code is numb to changes and prone to stumbling.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Implementing the Raft Consensus Algorithm with David Beazley</title>
        <published>2024-01-26T19:22:59+00:00</published>
        <updated>2024-01-26T19:22:59+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2024/01/26/implementing-the-raft-consensus-algorithm-with-david-beazley/"/>
        <id>https://briankung.dev/2024/01/26/implementing-the-raft-consensus-algorithm-with-david-beazley/</id>
        
        <content type="html" xml:base="https://briankung.dev/2024/01/26/implementing-the-raft-consensus-algorithm-with-david-beazley/">&lt;p&gt;I survived David Beazley&#x27;s weeklong course on the Raft consensus algorithm that powers technologies like Kubernetes, MongoDB, and Neo4j.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;raft.github.io&#x2F;&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;images&#x2F;solo.svg&quot; alt=&quot;A cute drawing of three logs tied together into one &amp;quot;Raft&amp;quot; with a smiling face&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Image from &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;raft.github.io&#x2F;&quot;&gt;https:&#x2F;&#x2F;raft.github.io&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The Raft Consensus Algorithm is a way for a gaggle of computers to agree on a sequence of events, or a &quot;log&quot; of events. Raft is useful for things like databases - once your data spans multiple computers, you will have consistency issues. Imagine a group of friends who want to go on vacation. They each have an itinerary in mind, but if each one has a different idea for what to do on a given day, there will be chaos. In this scenario, each friend is a computer and the itinerary is the sequence of events that they&#x27;re trying to keep synchronized.&lt;&#x2F;p&gt;
&lt;p&gt;In broad swaths, Raft is about keeping those logs synchronized through a democratic election process. Initially, every server starts out as a peer and then after a time, one will decide to solicit votes from their peers to become a leader. If a majority vote for that peer, then that server will become a leader and only then will the group as a whole become operational.&lt;&#x2F;p&gt;
&lt;p&gt;Going back to the vacation itinerary analogy, everyone starts out on the same page until one of the friends takes the initiative to start planning. Once everyone votes a leader in, people can start to add items to the itinerary by telling the leader, who then replicates those items to its followers.&lt;&#x2F;p&gt;
&lt;p&gt;Having a majority of servers operational and acknowledging the leader is crucial to this algorithm due to the fact that servers may go down, or the network may break down. This algorithm is intended to maintain availability in the face of failure. So only data that has been &quot;committed&quot; by a majority of the servers is acknowledged by the leader. If less than a majority of peers has been able to write an &quot;itinerary item,&quot; then that item is considered un-committed and can be overwritten by the next item that comes in.&lt;&#x2F;p&gt;
&lt;p&gt;There are countless more details that go into the algorithm, like timeouts triggering new elections in case a leader goes down, log replication rules for log entries that conflict with each other in case there are rogue leaders, and carefully tracking term and item numbers to validate that a leader is, in fact, legitimate, as well as concerns about how to interface with external applications.&lt;&#x2F;p&gt;
&lt;p&gt;The class, which Beazley calls &quot;Rafting Trip&quot; (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dabeaz.com&#x2F;raft.html&quot;&gt;https:&#x2F;&#x2F;dabeaz.com&#x2F;raft.html&lt;&#x2F;a&gt;), consisted of 30-60 minute long discussion sessions followed by up to 2 hours of coding, with a break in the middle around 1pm central time, and then another afternoon session. All in all, days went from 9:30am to 5:30pm. I was grateful to have my wife (who is also juggling work!) and my dad watching the kids while I focused on the class; otherwise this would have been impossible.&lt;&#x2F;p&gt;
&lt;p&gt;It was a humbling experience. For comparison, Beazley likened the complexity to writing an operating system by the last day (today), or even harder, and he would know since he taught the operating systems course at a university level.&lt;&#x2F;p&gt;
&lt;p&gt;Beazley&#x27;s instruction style was informal, but also probing. He treated us all as colleagues simply exploring an interesting and devilishly complex problem - he even coded a Raft implementation himself alongside us. It was really refreshing to be able to focus on a problem in depth with some like-minded programmers instead of playing kick-the-can with technical debt because of business needs.&lt;&#x2F;p&gt;
&lt;p&gt;I decided to attempt to use Rust to implement the challenge solutions, which was certainly &lt;em&gt;enlightening&lt;&#x2F;em&gt;, if exceedingly painful (in a good way, I promise).&lt;&#x2F;p&gt;
&lt;p&gt;Every time I choose Rust for a challenging programming problem it does its best to make me regret it, and then I come out with a stronger conviction to use it again next time. Rust&#x27;s appeal is mostly masochistic; convince me otherwise.&lt;&#x2F;p&gt;
&lt;p&gt;Since the algorithm has to do with multiple systems in play, I not only sharpened up on my multithreaded programming, but also on fundamentals of networking. Unfortunately, I didn&#x27;t get far enough along to have my multithreaded programs talk to each other, but I was able to get Udp packets sent from program to program and finally exercise my brain on the differences between sharing state within a thread (reference counted: &lt;code&gt;Rc&lt;&#x2F;code&gt;), across threads (atomically reference counted: &lt;code&gt;Arc&lt;&#x2F;code&gt;), and various mechanisms for sharing or mutating data like &lt;code&gt;RefCell&lt;&#x2F;code&gt;, &lt;code&gt;Mutex&lt;&#x2F;code&gt;, and &lt;code&gt;RwLock&lt;&#x2F;code&gt;, which are for interior mutability, mutually exclusive threadsafe access, and concurrent threadsafe access, respectively.&lt;&#x2F;p&gt;
&lt;p&gt;My strategy when implementing Raft&#x27;s election process was to focus on a &lt;code&gt;Channel&lt;&#x2F;code&gt; trait that I could mock out in order to mimic messages being sent. The thought was to make the system testable by faking interactions between servers, which I called &lt;code&gt;RaftBuddy&lt;&#x2F;code&gt;s because my brain was melting at the time and it amused me. Later, I could implement the &lt;code&gt;Channel&lt;&#x2F;code&gt; trait to actually talk to the network. Alas, everyone has a plan until the plan punches you in the face with a faulty Raft implementation.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;&#x2F;&#x2F; My poor vestigial Channel implementationuse crate::raft_message::RaftMessage;#[derive(PartialEq, Eq, Clone, Default)]pub struct RaftChannel {    pub queue: Vec&amp;lt;RaftMessage&amp;gt;,}pub trait Channel {    fn push(&amp;amp;mut self, message: RaftMessage);    fn pop(&amp;amp;mut self) -&amp;gt; Option&amp;lt;RaftMessage&amp;gt;;    fn all_messages(&amp;amp;mut self) -&amp;gt; Vec&amp;lt;RaftMessage&amp;gt;;}impl Channel for RaftChannel {    fn push(&amp;amp;mut self, message: RaftMessage) {        todo!()    }    fn pop(&amp;amp;mut self) -&amp;gt; Option&amp;lt;RaftMessage&amp;gt; {        todo!()    }    fn all_messages(&amp;amp;mut self) -&amp;gt; Vec&amp;lt;RaftMessage&amp;gt; {        todo!()    }}#[derive(PartialEq, Eq, Clone, Default)]struct TestRaftChannel {    queue: Vec&amp;lt;RaftMessage&amp;gt;,}impl Channel for TestRaftChannel {    fn push(&amp;amp;mut self, message: RaftMessage) {        self.queue.push(message);    }    fn pop(&amp;amp;mut self) -&amp;gt; Option&amp;lt;RaftMessage&amp;gt; {        self.queue.pop()    }    fn all_messages(&amp;amp;mut self) -&amp;gt; Vec&amp;lt;RaftMessage&amp;gt; {        self.queue.clone()    }}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;em&gt;(Do I actually think &lt;code&gt;all_messages&lt;&#x2F;code&gt; is a good idea as a public interface? No, but it made testing easier and I was more focused on desperately shoving the wreckage of my Raft implementation around, like a college student trying to make his dorm room presentable before his parents visit.)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I got as far as leader elections requiring a majority before the end of the week. A lot of it was managing my energy levels. Oftentimes, I would just lie on the floor and cry think about the problem. I thought this was going to be difficult coming in, and I still underestimated how difficult it was.&lt;&#x2F;p&gt;
&lt;p&gt;If I were to go back in time, I would probably make a point to do the projects in Ruby. It was hard enough to complete the projects, but learning the proper data structures to do multithreaded Rust as well definitely distracted from the Raft algorithm itself. However, now that I&#x27;ve stumbled through an initial attempt, I am pretty happy with what I learned and if I were to &lt;em&gt;redo&lt;&#x2F;em&gt; the course, I&#x27;d gladly do it in Rust again.&lt;&#x2F;p&gt;
&lt;p&gt;On that point, it did seem like Rust&#x27;s type safety, when applied to multithreaded code, did end up having some advantages over the dynamically typed Python code that many of my classmates were using. While we all wrote multithreaded code, Rust&#x27;s enforcement of the appropriate data types gave me a lot more trouble upfront, whereas other participants in the class seemed to have more issues debugging issues with shared mutable state. So I&#x27;m not sure a Ruby rewrite would be much easier - rather, it would just present a different set of problems.&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s why when David asked what we would do differently, my only real feedback was that I would have started a month ago. The algorithm is so heinously complex that I don&#x27;t think any particular change would have been any easier. I&#x27;m certain I would have faced just as many issues in the end.&lt;&#x2F;p&gt;
&lt;p&gt;This course and the algorithm were both ridiculously difficult, humbling, and extremely painful. I would highly recommend taking it if you ever have a chance, and now I&#x27;m eyeing David Beazley&#x27;s other courses as well.&lt;&#x2F;p&gt;
&lt;p&gt;Links:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;raft.github.io&#x2F;&quot;&gt;https:&#x2F;&#x2F;raft.github.io&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;briankung&#x2F;rafting_trip&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;briankung&#x2F;rafting_trip&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dabeaz.com&#x2F;raft.html&quot;&gt;https:&#x2F;&#x2F;dabeaz.com&#x2F;raft.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;dabeaz.com&#x2F;courses.html&quot;&gt;http:&#x2F;&#x2F;dabeaz.com&#x2F;courses.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Staff Engineer by Will Larson</title>
        <published>2023-07-27T09:11:30+00:00</published>
        <updated>2023-07-27T09:11:30+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2023/07/27/staff-engineer-by-will-larson/"/>
        <id>https://briankung.dev/2023/07/27/staff-engineer-by-will-larson/</id>
        
        <content type="html" xml:base="https://briankung.dev/2023/07/27/staff-engineer-by-will-larson/">&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;staffeng.com&#x2F;book&quot;&gt;Staff Engineer by Will Larson&lt;&#x2F;a&gt; talks about what happens in your career should you decide to progress past Senior Engineer. For context, software engineers typically progress through a series of well known levels: junior, mid (or just &quot;engineer&quot;), and senior.&lt;&#x2F;p&gt;
&lt;p&gt;All of these levels are characterized by increasing autonomy and impact:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Title&lt;&#x2F;th&gt;&lt;th&gt;Autonomy&lt;&#x2F;th&gt;&lt;th&gt;Impact&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Junior Engineer&lt;&#x2F;td&gt;&lt;td&gt;Needs direction&lt;&#x2F;td&gt;&lt;td&gt;Needs assistance completing tasks&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Mid-level Engineer&lt;&#x2F;td&gt;&lt;td&gt;Self-directed for day to day tasks&lt;&#x2F;td&gt;&lt;td&gt;Independently completes tasks&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Senior Engineer&lt;&#x2F;td&gt;&lt;td&gt;Self-directed, assists with team direction&lt;&#x2F;td&gt;&lt;td&gt;Independently completes tasks with high level of quality&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Senior Engineer is what&#x27;s called a &quot;terminal level,&quot; meaning you could spend the rest of your career as a senior engineer. Basically it&#x27;s an equilibrium point; another way to think of it is that you won&#x27;t be let go for deciding *not* to go for a promotion, whereas for more junior positions that is generally not true (though I feel like Engineers get by just fine in my experience).&lt;&#x2F;p&gt;
&lt;p&gt;Staff plus levels, meaning Staff &#x2F; Principal &#x2F; Fellow &#x2F; Distinguished Engineers are engineers who are still individual contributors, but nonetheless take on leadership roles. So the table begins to look like this:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Title&lt;&#x2F;th&gt;&lt;th&gt;Autonomy&lt;&#x2F;th&gt;&lt;th&gt;Impact&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Staff Engineer&lt;&#x2F;td&gt;&lt;td&gt;Influences a team or division&lt;&#x2F;td&gt;&lt;td&gt;Affects the output of team members&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Principal Engineer&lt;&#x2F;td&gt;&lt;td&gt;Influences the organization&lt;&#x2F;td&gt;&lt;td&gt;Affects the output of teams&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Distinguished Engineer&lt;&#x2F;td&gt;&lt;td&gt;Influences the industry&lt;&#x2F;td&gt;&lt;td&gt;Affects the industry&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Each subsequent level comes with increasing understanding of the business domain and increasing organizational trust in their abilities to do what&#x27;s best for the business.&lt;&#x2F;p&gt;
&lt;p&gt;Q: So if it&#x27;s a leadership role, what&#x27;s the difference between Staff+ and going into management?&lt;&#x2F;p&gt;
&lt;p&gt;A: The difference is in the reporting structure. As a staff+ engineer, you&#x27;re not in the chain of command and it&#x27;s not typically your job to do performance reviews, 1:1&#x27;s, or firing, yet you have the mandate to operate outside of your immediate chain of command in order to maximize impact on the organization. This lets you &quot;go to ground&quot; among your fellow engineers and get their unfiltered opinions on the state of engineering in the organization without fear of managerial retribution. The difference is that staff+ roles are about soft power leadership, whereas managers are endowed with institutional power, which changes the relationship with other individual contributors.&lt;&#x2F;p&gt;
&lt;p&gt;Also, sometimes being a force multiplier for a team can mean improving developer experience, platform engineering improvements, changing the onboarding or hiring processes, introducing a new technology, or promoting a psychologically safe working environment.&lt;&#x2F;p&gt;
&lt;p&gt;Larson&#x27;s book covers four archetypes of Staff+ engineers that stuck with me:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;The Team Lead - the most common Staff+ archetype, the team lead is responsible for leading a team on an initiative or a domain.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;The Solver - the solver finds hot spots or particularly thorny problems and fixes them, often bouncing from problem to problem. Interestingly Larson notes that this archetype shows up in orgs with a &quot;weak team concept.&quot;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;The Architect - the architect is responsible for architecting new solutions. This sounds simple, but good architecture accounts for brownfield projects as well, meaning incremental architectures like the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;learn.microsoft.com&#x2F;en-us&#x2F;azure&#x2F;architecture&#x2F;patterns&#x2F;strangler-fig&quot;&gt;strangler fig pattern&lt;&#x2F;a&gt; come into play.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;The Right Hand - the right hand is the least intuitive to me. To my understanding, it&#x27;s a form of very deep delegation to engineering leaders who act as representatives of an individual or an office. They force multiply leadership instead of force multiplying individual contributors like many of the other archetypes do.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;After discussing the archetypes, the book then goes into tips for how to operate as a Staff+ engineer, then how to get the position, whether that&#x27;s at your current company or otherwise, then filled the last half of the book with all the source interviews that the author did with Staff+ engineers.&lt;&#x2F;p&gt;
&lt;p&gt;Overall, the book covered a lot of ground - almost too much, because it will often allude to linked articles that aren&#x27;t summarized at all. I do think it would have benefited from a professional editor. However, while the book feels a bit like a long blog post, it&#x27;s still very useful and does well in conveying the overall idea of the various Staff+ positions.&lt;&#x2F;p&gt;
&lt;p&gt;I found the interviews at the end possibly more useful than the first half of the book in terms of getting an idea of what real staff+ engineers do - having cohesive stories makes it easier to remember them, even though I had read excerpts from the interviews in the first half of the book.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m very curious to compare this to Tanya Reilly&#x27;s book, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.oreilly.com&#x2F;library&#x2F;view&#x2F;the-staff-engineers&#x2F;9781098118723&#x2F;&quot;&gt;The Staff Engineer&#x27;s Path&lt;&#x2F;a&gt;, which is up next.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>A random assortment of Rust notes</title>
        <published>2023-07-16T06:02:27+00:00</published>
        <updated>2023-07-16T06:02:27+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2023/07/16/rust-notes/"/>
        <id>https://briankung.dev/2023/07/16/rust-notes/</id>
        
        <content type="html" xml:base="https://briankung.dev/2023/07/16/rust-notes/">&lt;p&gt;I thought I&#x27;d jot down some notes about using Rust that wouldn&#x27;t have made it as their own blog posts:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;briankung.dev&#x2F;2023&#x2F;07&#x2F;16&#x2F;rust-notes&#x2F;#you-can-t-use-anonymous-functions-for-control-flow&quot;&gt;You can&#x27;t use anonymous functions for control flow&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;briankung.dev&#x2F;2023&#x2F;07&#x2F;16&#x2F;rust-notes&#x2F;#the-build-times&quot;&gt;The build times&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;briankung.dev&#x2F;2023&#x2F;07&#x2F;16&#x2F;rust-notes&#x2F;#traits-traits-traits-and-more-traits&quot;&gt;Traits, traits, traits, and more traits&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;briankung.dev&#x2F;2023&#x2F;07&#x2F;16&#x2F;rust-notes&#x2F;#keeping-up-with-rust-news&quot;&gt;Keeping up with Rust news&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;you-can-t-use-anonymous-functions-for-control-flow&quot;&gt;You can&#x27;t use anonymous functions for control flow&lt;&#x2F;h2&gt;
&lt;p&gt;In Ruby, you can &lt;code&gt;return&lt;&#x2F;code&gt; from almost anywhere in a function:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;def&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; find_even&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;font-style: italic;&quot;&gt; arr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  arr&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;each&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {|&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;|&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt; return&lt;&#x2F;span&gt;&lt;span&gt; i &lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;even?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;#=&amp;gt; :find_even&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;find_even &lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;#=&amp;gt; 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Unfortunately, it also returns nonsense if the inputs break the invariant that an even number exists in the set:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;return_even &lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #179299;&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is due to the expression &lt;code&gt;arr.each { ... }&lt;&#x2F;code&gt; returning &lt;code&gt;arr&lt;&#x2F;code&gt; by default.&lt;&#x2F;p&gt;
&lt;p&gt;In Rust, the &lt;code&gt;return&lt;&#x2F;code&gt; keyword is much more predictable - it returns from the immediate functional scope, regardless of whether it&#x27;s an anonymous function or not, meaning you can&#x27;t use anonymous functions in Rust the same way you&#x27;d use block syntax in Ruby for control flow. So this code, which is roughly equivalent to the Ruby, doesn&#x27;t compile:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; find_even&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;&quot;&gt;arr&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;])&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt; u8&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    arr&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;iter&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;for_each&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;|&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span&gt; i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; %&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;            return&lt;&#x2F;span&gt;&lt;span&gt; i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;    });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;    &#x2F;&#x2F; Can&amp;#39;t return null or self array, so return default 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;    0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This also returns nonsense, but at least it&#x27;s nonsense during compilation and not during runtime where people might actually see it:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;error[E0308]: mismatched types&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; --&amp;gt; src&#x2F;main.rs:4:20&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4 |             return i;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  |                    ^ expected `()`, found `&amp;amp;u8`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;note: return type inferred to be `()` here&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; --&amp;gt; src&#x2F;main.rs:4:20&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4 |             return i;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  |                    ^&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;For more information about this error, try `rustc --explain E0308`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;error: could not compile `play` (bin &amp;quot;play&amp;quot;) due to previous error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This error just means that we&#x27;re trying to return a &lt;code&gt;&amp;amp;u8&lt;&#x2F;code&gt; from within the anonymous function consumed by &lt;code&gt;for_each&lt;&#x2F;code&gt;, and &lt;code&gt;for_each&lt;&#x2F;code&gt; doesn&#x27;t expect any such returned value.&lt;&#x2F;p&gt;
&lt;p&gt;If you find yourself in such a bind, break your higher order function out into a control flow mechanism that doesn&#x27;t create a new functional scope:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; find_even&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;&quot;&gt;arr&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;])&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt; u8&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span&gt; i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt; in&lt;&#x2F;span&gt;&lt;span&gt; arr&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;iter&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span&gt; i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; %&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;            return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;    0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;💡 Note: llogiq mentioned that you can easily replace this with a call to &lt;code&gt;find()&lt;&#x2F;code&gt; to keep using functional style method chaining. Do that! This was just a contrived example.&lt;&#x2F;p&gt;
&lt;p&gt;💡 Note #2: Oliver M. S. from LinkedIn alerted me to the &lt;code&gt;[core::ops::ControlFlow](https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;beta&#x2F;core&#x2F;ops&#x2F;enum.ControlFlow.html)&lt;&#x2F;code&gt; trait used with &lt;code&gt;try_*&lt;&#x2F;code&gt; methods like &lt;code&gt;try_for_each&lt;&#x2F;code&gt; that generalizes this kind of thing. Holy shit, it responds to &lt;code&gt;?&lt;&#x2F;code&gt; like Result and Option? That&#x27;s slick. 🔥&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-build-times&quot;&gt;The build times&lt;&#x2F;h2&gt;
&lt;p&gt;A recent &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;opensource.googleblog.com&#x2F;2023&#x2F;06&#x2F;rust-fact-vs-fiction-5-insights-from-googles-rust-journey-2022.html&quot;&gt;Google blog post&lt;&#x2F;a&gt; contained some great news for Rust: it&#x27;s no more or no less difficult to learn than other languages. It also noted some room for improvement:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;Slow build speeds were by far the #1 reported challenge that developers have when using Rust, with only a little more than 40% of respondents finding the speed acceptable.&quot;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Abi Noda, a developer experience evangelist, also recently wrote &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;pulse&#x2F;build-times-developer-productivity-abi-noda&quot;&gt;a newsletter&lt;&#x2F;a&gt; covering a study on build time effects on developer effectiveness. That study found that the relationship between build times and likelihood of a developer completing a task was linear - that is, any reduction in build times is an increase in the likelihood of completing a task.&lt;&#x2F;p&gt;
&lt;p&gt;In my experience, the build times have been noticeable, though my overall experience is that it&#x27;s less painful overall than the dice roll that is building nokogiri on a legacy Rails code base.&lt;&#x2F;p&gt;
&lt;p&gt;Still, it&#x27;s important to note that you can reduce local buildtimes by a significant proportion just by using &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mozilla&#x2F;sccache&quot;&gt;sccache&lt;&#x2F;a&gt;. sccache is a caching mechanism by Mozilla that wraps calls to the Rust compiler and speeds up build times by caching compilation artifacts. If you&#x27;re using GitHub Actions, sccache has a GitHub Actions&#x27; cache API &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mozilla&#x2F;sccache&#x2F;blob&#x2F;main&#x2F;docs&#x2F;GHA.md&quot;&gt;backend&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Just using &lt;code&gt;sccache&lt;&#x2F;code&gt; in CI netted us a 18% build time improvement. Locally, I saw much better results on the order of 50% build time reductions, probably because it&#x27;s not making network calls to a remote caching service.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;traits-traits-traits-and-more-traits&quot;&gt;Traits, traits, traits, and more traits&lt;&#x2F;h2&gt;
&lt;p&gt;It&#x27;s hard to overstate the importance of traits in Rust. To use Ruby as an example again, the method resolution algorithm goes roughly through these steps:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Is the method defined on the object?&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Is the method defined on the class of the object?&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Is the method defined on any parent classes?&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;If so, it will execute the method found on the object, class, or class hierarchy. Basically every time you ask Ruby to perform a task, it shuffles through its pant pockets, then jacket pockets, then its parents&#x27; pockets until it finds something suitable and hands it off to you.&lt;&#x2F;p&gt;
&lt;p&gt;Rust, on the other hand, must know not just that it has the thing you&#x27;re looking for, but that the thing you&#x27;re interacting with conforms to the exact behavior you&#x27;re looking for. Instead of asking &quot;is the method here?&quot; Rust asks &quot;is this the &lt;em&gt;kind&lt;&#x2F;em&gt; of thing you&#x27;re even looking for?&quot; To compare:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;What type of thing is this?&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;What trait, or types of behaviors, does it implement?&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;What trait is being requested? i.e. just because a trait defines the same methods as another one doesn&#x27;t mean they are equivalent.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This is far more correct, but can be onerous to deal with. Instead of shuffling through pockets, it&#x27;s more akin to registering for a passport. Your data structures are citizens of certain countries and if they apply for a passport and meet the requirements, they can travel to other countries. However, their statuses must be known before their travel privileges are. Pockets will be pre-searched by the Rustc Traits Authority.&lt;&#x2F;p&gt;
&lt;p&gt;Traits are the passports of the Rust ecosystem. If you&#x27;re using a third party library, you may need to implement a trait in order to use the library on your data structures. Alternately, a library may lean on traits already implemented in the standard library to operate. Either way, it&#x27;s traits all the way down. 🐢&lt;&#x2F;p&gt;
&lt;h2 id=&quot;keeping-up-with-rust-news&quot;&gt;Keeping up with Rust news&lt;&#x2F;h2&gt;
&lt;p&gt;I have a short list of places I go to for Rust related news and community:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;this-week-in-rust.org&#x2F;&quot;&gt;https:&#x2F;&#x2F;this-week-in-rust.org&#x2F;&lt;&#x2F;a&gt; - this weekly newsletter is my favorite avenue for keeping up. It includes the community&#x27;s blog posts, which you can submit yourself, community events (in-person and online), a quote of the week which I am especially fond of, and more. If you do nothing else, sign up for this mailing list.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;old.reddit.com&#x2F;r&#x2F;rust&#x2F;&quot;&gt;https:&#x2F;&#x2F;old.reddit.com&#x2F;r&#x2F;rust&#x2F;&lt;&#x2F;a&gt; - I don&#x27;t agree with where Reddit is going [&lt;a href=&quot;https:&#x2F;&#x2F;briankung.dev&#x2F;2023&#x2F;07&#x2F;16&#x2F;rust-notes&#x2F;#enshittification&quot;&gt;0&lt;&#x2F;a&gt;] and I see a lot less activity here than I used to, but it was the most active and dynamic Rust community for a long time and a lot of good discussion has happened on this subreddit.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;users.rust-lang.org&#x2F;&quot;&gt;https:&#x2F;&#x2F;users.rust-lang.org&#x2F;&lt;&#x2F;a&gt; - My new haunt for community related stuff. Go here and post! It&#x27;s a lot slower, but slow can be good.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;lobste.rs&#x2F;t&#x2F;rust&quot;&gt;https:&#x2F;&#x2F;lobste.rs&#x2F;t&#x2F;rust&lt;&#x2F;a&gt; - Lobste.rs is a technical community where a lot of good discussion happens. Also less active than Reddit, but generally the quality of discussion is better.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;&quot;&gt;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;&lt;&#x2F;a&gt; - Of course the orange site. Rust is beyond the point where &quot;written in Rust&quot; means an automatic frontpage on Hacker News, and is, in terms of technology almost boring for perpetually online folk like myself, but bigger announcements will often have good technical discussions. You can count on this crowd to start fights about having a Code of Conduct, though. In terms of psychological safety, Rust project (meaning Foundation + community) moderated spaces feel much safer.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Finally, just following #rustlang on Mastodon. I&#x27;d say Twitter, but I &lt;em&gt;*sigh*&lt;&#x2F;em&gt; can&#x27;t really endorse using Twitter [&lt;a href=&quot;https:&#x2F;&#x2F;briankung.dev&#x2F;2023&#x2F;07&#x2F;16&#x2F;rust-notes&#x2F;#enshittification&quot;&gt;0&lt;&#x2F;a&gt;].&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I don&#x27;t do Discord unless I have specific questions, I don&#x27;t do video platforms because I don&#x27;t have the time and it aggros my kids, and I also don&#x27;t do podcasts because there haven&#x27;t been any ongoing Rust-specific podcasts that I&#x27;ve liked (and I&#x27;m aware of Rustacean Station). I did enjoy &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;newrustacean.com&#x2F;&quot;&gt;New Rustacean&lt;&#x2F;a&gt;, which was about learning Rust, and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;podcasts.apple.com&#x2F;us&#x2F;podcast&#x2F;building-with-rust&#x2F;id1553513574&quot;&gt;Building with Rust&lt;&#x2F;a&gt;, which is a series of interviews, but they have both unfortunately come to an end, or so it seems.&lt;&#x2F;p&gt;
&lt;p&gt;Another angle to take is not just &quot;where,&quot; but &quot;who.&quot; I find these people worthwhile to follow:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;thesquareplanet.com&#x2F;&quot;&gt;Jon Gjengset&lt;&#x2F;a&gt; - A prolific YouTuber and Rust personality who is renowned for long, in-depth live coding adventures. I will admit, I have not gotten through a single live coding video. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;playlist?list=PLqbS7AVVErFiWDOAVrPt7aYmnuuOLYvOa&quot;&gt;Crust of Rust&lt;&#x2F;a&gt; is a great series and I &lt;em&gt;have&lt;&#x2F;em&gt; finished sitting through one of those, however.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;m_ou_se?lang=en&quot;&gt;Mara Bos&lt;&#x2F;a&gt; - Rust Lang Library team lead and author of Rust Atomics and Locks, Mara&#x27;s posts always pop up on my feeds explaining neat new features in Rust releases.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Aria Beingessner &#x2F; Gankra - author of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;rust-unofficial.github.io&#x2F;too-many-lists&#x2F;&quot;&gt;Learning Rust With Entirely Too Many Linked Lists&lt;&#x2F;a&gt; and author of cargo-dist and oranda at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;axo.dev&#x2F;&quot;&gt;axo.dev&lt;&#x2F;a&gt;, Gankra has a deep understanding of Rust. Make sure to check out their blog: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;faultlore.com&#x2F;blah&#x2F;&quot;&gt;https:&#x2F;&#x2F;faultlore.com&#x2F;blah&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.burntsushi.net&#x2F;about&#x2F;&quot;&gt;Andrew Gallant &#x2F; burntsushi&lt;&#x2F;a&gt; - I struggled to remember burntsushi&#x27;s IRL name because they&#x27;re so prolific on reddit. They&#x27;re the author of the regex implementation in Rust and when they comment online they&#x27;re generous with benefit of the doubt and excellent at explaining themselves.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fasterthanli.me&#x2F;&quot;&gt;Amos Wenger &#x2F; fasterthanlime&lt;&#x2F;a&gt; - Amos is another incredibly prolific YouTuber and blogger. Many a time I have loaded up a new fasterthanlime article, glanced at the estimated read time, and realized I would not be finishing the article in one sitting.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;There are tons of helpful people in the Rust community - this is just a sample off the top of my head.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;[0]: &lt;em&gt;&quot;Pluralistic: Tiktok&#x27;s enshittification (21 Jan 2023)&quot; - &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pluralistic.net&#x2F;2023&#x2F;01&#x2F;21&#x2F;potemkin-ai&#x2F;&quot;&gt;https:&#x2F;&#x2F;pluralistic.net&#x2F;2023&#x2F;01&#x2F;21&#x2F;potemkin-ai&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>One of my favorite Rust features (doc comments!)</title>
        <published>2023-05-20T17:29:09+00:00</published>
        <updated>2023-05-20T17:29:09+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2023/05/20/one-of-my-favorite-rust-features/"/>
        <id>https://briankung.dev/2023/05/20/one-of-my-favorite-rust-features/</id>
        
        <content type="html" xml:base="https://briankung.dev/2023/05/20/one-of-my-favorite-rust-features/">&lt;p&gt;I realized that one of my favorite Rust features doesn&#x27;t have a blog post highlighting it [&lt;a href=&quot;https:&#x2F;&#x2F;briankung.dev&#x2F;2023&#x2F;05&#x2F;20&#x2F;one-of-my-favorite-rust-features&#x2F;#0&quot;&gt;0&lt;&#x2F;a&gt;], so I thought I&#x27;d talk a bit about documentation comments and doc tests in Rust.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ll give you a quick example. Let&#x27;s say you have some code:&lt;&#x2F;p&gt;
&lt;p&gt;[![```
&#x2F;&#x2F; src&#x2F;lib.rs&lt;&#x2F;p&gt;
&lt;div&gt;&lt;&#x2F;div&gt;
&#x2F;&#x2F;&#x2F; Guaranteed to be a very cute puppy
pub struct Puppy {
pub name: String,
}
\`\`\`](&#x2F;assets&#x2F;images&#x2F;carbon1-3.png)](&#x2F;assets&#x2F;images&#x2F;carbon1-3.png)
&lt;p&gt;There&#x27;s a &lt;code&gt;cargo&lt;&#x2F;code&gt; command to generate documentation from that code:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;images&#x2F;screenshot-2023-05-20-at-3.55.31-pm.png&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;images&#x2F;screenshot-2023-05-20-at-3.55.31-pm.png&quot; alt=&quot;A terminal window showing just the command `cargo doc --open`&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Which results in automatically generated documentation that looks like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;images&#x2F;screenshot-2023-05-20-at-3.57.07-pm.png&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;images&#x2F;screenshot-2023-05-20-at-3.57.07-pm.png&quot; alt=&quot;A screenshot of a Rust project, or crate, called &amp;quot;play&amp;quot; with a single struct, Puppy, with no additional description.&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In any other language before learning Rust, I would have been pretty impressed at this point [&lt;a href=&quot;https:&#x2F;&#x2F;briankung.dev&#x2F;2023&#x2F;05&#x2F;20&#x2F;one-of-my-favorite-rust-features&#x2F;#1&quot;&gt;1&lt;&#x2F;a&gt;]. The fact that documentation can be generated with a single command with the default toolchain, no added components? Pretty good already. But Rust lets you take it several steps further with documentation comments.&lt;&#x2F;p&gt;
&lt;p&gt;You already saw the code comment in the screenshot indicating what file I was referring to. That looked like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;images&#x2F;carbon3.png&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;images&#x2F;carbon3.png&quot; alt=&quot;&#x2F;&#x2F; src&#x2F;lib.rs&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Rust also supports a triple slash comment like this:&lt;&#x2F;p&gt;
&lt;p&gt;[![&#x2F;&#x2F; src&#x2F;lib.rs&lt;&#x2F;p&gt;
&lt;div&gt;&lt;&#x2F;div&gt;
&#x2F;&#x2F;&#x2F; Guaranteed to be a very cute puppy
pub struct Puppy {
pub name: String,
}](&#x2F;assets&#x2F;images&#x2F;carbon2-1.png)](&#x2F;assets&#x2F;images&#x2F;carbon2-1.png)
&lt;p&gt;That third slash is not just decorative. Let&#x27;s rerun &lt;code&gt;cargo doc&lt;&#x2F;code&gt; and refresh our generated documentation:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;images&#x2F;screenshot-2023-05-20-at-4.04.12-pm.png&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;images&#x2F;screenshot-2023-05-20-at-4.04.12-pm.png&quot; alt=&quot;A screenshot of a Rust project, or crate, called &amp;quot;play&amp;quot; with a single struct, Puppy, with the description &amp;quot;Guaranteed to be a very cute puppy.&amp;quot;&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Et voilà! The description has appeared in the documentation. And that&#x27;s not all. You can even annotate individual fields.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;images&#x2F;carbon8.png&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;images&#x2F;carbon8.png&quot; alt=&quot;&#x2F;&#x2F;&#x2F; Guaranteed to be a very cute puppy pub struct Puppy { &#x2F;&#x2F;&#x2F; The answer to &amp;quot;Who&amp;#39;s a good lil puppy? 🥰&amp;quot; pub name: String, }&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;And clicking through to the detail view of the struct gives you the description as well as annotations on the fields:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;images&#x2F;screenshot-2023-05-20-at-4.11.24-pm.png&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;images&#x2F;screenshot-2023-05-20-at-4.11.24-pm.png&quot; alt=&quot;Same screenshot as earlier, but the `name: String` has a description as well: The answer to &amp;quot;Who&amp;#39;s a good lil puppy? 🥰&amp;quot;&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Ah, but that&#x27;s (still) not all. Rust&#x27;s documentation tooling solves yet another problem. Let&#x27;s say you have an method on &lt;code&gt;Puppy&lt;&#x2F;code&gt; like so:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;images&#x2F;carbon10.png&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;images&#x2F;carbon10.png&quot; alt=&quot;impl Puppy { pub fn whos_good(self) -&amp;gt; String { self.name } }&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;You might want to document it in a code comment like so:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;images&#x2F;carbon11.png&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;images&#x2F;carbon11.png&quot; alt=&quot;impl Puppy { &#x2F;&#x2F; This responds with the puppy&amp;#39;s name: &#x2F;&#x2F; let roscoe = Puppy { name: &amp;quot;Roscoe&amp;quot;.to_string() }; &#x2F;&#x2F; roscoe.whos_good() == &amp;quot;Roscoe&amp;quot;; &#x2F;&#x2F; true pub fn whos_good(self) -&amp;gt; String { self.name } } &quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;But let&#x27;s say that &lt;code&gt;whos_good&lt;&#x2F;code&gt; ended up changing for some reason, for example if &lt;code&gt;Puppy&lt;&#x2F;code&gt; was refactored to have a &lt;code&gt;first_name&lt;&#x2F;code&gt; and &lt;code&gt;last_name&lt;&#x2F;code&gt; instead ()&lt;&#x2F;p&gt;
&lt;p&gt;[![&#x2F;&#x2F;&#x2F; Guaranteed to be a very cute puppy
pub struct Puppy {
&#x2F;&#x2F;&#x2F; The answer to &quot;Who&#x27;s a good lil puppy? 🥰&quot;
pub first_name: String,
pub last_name: String,
}&lt;&#x2F;p&gt;
&lt;div&gt;&lt;&#x2F;div&gt;
impl Puppy {
&#x2F;&#x2F; This responds with the puppy&#x27;s name:
&#x2F;&#x2F; let roscoe = Puppy { name: &quot;Roscoe&quot;.to\_string() };
&#x2F;&#x2F; ❌🚧❌ Uh oh! This 👇 is no longer true ❌🚧❌
&#x2F;&#x2F; roscoe.whos\_good() == &quot;Roscoe&quot;; &#x2F;&#x2F; true
pub fn whos\_good(self) -&gt; String {
format!(&quot;{} {}&quot;, self.first\_name, self.last\_name)
}
}](&#x2F;assets&#x2F;images&#x2F;carbon15.png)](&#x2F;assets&#x2F;images&#x2F;carbon15.png)
&lt;p&gt;&lt;em&gt;Aside: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.kalzumeus.com&#x2F;2010&#x2F;06&#x2F;17&#x2F;falsehoods-programmers-believe-about-names&#x2F;&quot;&gt;Falsehoods Programmers Believe About Names&lt;&#x2F;a&gt; is a great read.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Now our comment block is out of date! Luckily, Rust supports one more feature that helps keep code comments from going stale: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;rustdoc&#x2F;write-documentation&#x2F;documentation-tests.html&quot;&gt;Documentation tests&lt;&#x2F;a&gt;. For context, doc comments are written in markdown. By default, markdown code blocks in documentation comments are &lt;em&gt;executed as code&lt;&#x2F;em&gt;. That&#x27;s right, in Rust even your code comments are Turing-complete.&lt;&#x2F;p&gt;
&lt;p&gt;If we rewrite our comment &lt;em&gt;just so&lt;&#x2F;em&gt;, we can get &lt;code&gt;cargo test&lt;&#x2F;code&gt; to run that assertion instead of relegating it to the dust bins of version control. Look! VS Code even uses appropriate syntax highlighting in the doc test block:&lt;&#x2F;p&gt;
&lt;p&gt;[![Screenshot of VS Code where the doc test is highlighted in the appropriated syntax. Code for the function and doc test below:&lt;&#x2F;p&gt;
&lt;div&gt;&lt;&#x2F;div&gt;
&#x2F;&#x2F;&#x2F; This responds with the puppy&#x27;s name:
&#x2F;&#x2F;&#x2F; \`\`\`
&#x2F;&#x2F;&#x2F; use play::Puppy;
&#x2F;&#x2F;&#x2F;
&#x2F;&#x2F;&#x2F; let roscoe = Puppy {
&#x2F;&#x2F;&#x2F;     first\_name: &quot;Roscoe&quot;.to\_string(),
&#x2F;&#x2F;&#x2F;     last\_name: &quot;McPuppyFace&quot;.to\_string(),
&#x2F;&#x2F;&#x2F; };
&#x2F;&#x2F;&#x2F; assert\_eq!(roscoe.whos\_good(), &quot;Roscoe&quot;);
&#x2F;&#x2F;&#x2F; \`\`\`
pub fn whos\_good(self) -&gt; String {
format!(&quot;{} {}&quot;, self.first\_name, self.last\_name)
}
](&#x2F;assets&#x2F;images&#x2F;screenshot-2023-05-20-at-4.59.32-pm.png)](&#x2F;assets&#x2F;images&#x2F;screenshot-2023-05-20-at-4.59.32-pm.png)
&lt;p&gt;And the test will run with the rest of the unit tests when you run &lt;code&gt;cargo test&lt;&#x2F;code&gt;, but for our screenshot&#x27;s sake, let&#x27;s just specify the documentation tests for now with &lt;code&gt;cargo test --doc&lt;&#x2F;code&gt; and silence the backtrace with &lt;code&gt;RUST_BACKTRACE=0&lt;&#x2F;code&gt;. So the full command is &lt;code&gt;RUST_BACKTRACE=0 cargo test --doc&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;images&#x2F;screenshot-2023-05-20-at-5.03.14-pm.png&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;images&#x2F;screenshot-2023-05-20-at-5.03.14-pm.png&quot; alt=&quot;Screenshot of the output of the cargo test output, mainly to show that the doc test assertion failed with left = &amp;quot;Roscoe McPuppyFace&amp;quot; and right = &amp;quot;Roscoe.&amp;quot;&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;And if we fix the documentation...&lt;&#x2F;p&gt;
&lt;p&gt;[![Screenshot of VS Code where the assertion has been modified to be:&lt;&#x2F;p&gt;
&lt;div&gt;&lt;&#x2F;div&gt;
assert\_eq!(roscoe.whos\_good(), &quot;Roscoe McPuppyFace&quot;);](&#x2F;assets&#x2F;images&#x2F;screenshot-2023-05-20-at-5.07.49-pm.png)](&#x2F;assets&#x2F;images&#x2F;screenshot-2023-05-20-at-5.07.49-pm.png)
&lt;p&gt;...we fix the tests:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;images&#x2F;screenshot-2023-05-20-at-5.09.57-pm.png&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;images&#x2F;screenshot-2023-05-20-at-5.09.57-pm.png&quot; alt=&quot;cargo test --doc passing!&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;And look at that slick documentation!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;images&#x2F;screenshot-2023-05-20-at-5.11.39-pm.png&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;images&#x2F;screenshot-2023-05-20-at-5.11.39-pm.png&quot; alt=&quot;Screenshot of updated Puppy struct documentation with nicely syntax highlighted code block describing the whos_good function&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I loooove Rust&#x27;s documentation features. It&#x27;s one of those tools that work so well that I end up &lt;em&gt;wanting&lt;&#x2F;em&gt; to document my code if nothing else just to admire the documentation later. I loved it so much I set up a GitHub Actions workflow at work to publish our documentation to our repo&#x27;s GitHub Pages so all my coworkers could admire their handiwork as well.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bonus-github-action&quot;&gt;Bonus: GitHub Action&lt;&#x2F;h2&gt;
&lt;p&gt;More on that last part. I&#x27;m not going to go into too much detail here, but on your repo you can set the Page to deploy from a GitHub Actions workflow:&lt;&#x2F;p&gt;
&lt;p&gt;[![Screenshot showing the settings for https:&#x2F;&#x2F;github.com&#x2F;user_name&#x2F;repo_name&#x2F;settings&#x2F;pages where user_name and repo_name are your user and repo.&lt;&#x2F;p&gt;
&lt;div&gt;&lt;&#x2F;div&gt;
Under &quot;Source&quot; you can select &quot;GitHub Actions&quot; or &quot;Deploy from a branch.&quot; We want to deploy from GitHub Actions.](&#x2F;assets&#x2F;images&#x2F;screenshot-2023-05-20-at-5.20.22-pm.png)](&#x2F;assets&#x2F;images&#x2F;screenshot-2023-05-20-at-5.20.22-pm.png)
&lt;p&gt;Then you can use the workflow below to deploy your documentation on every merge to a branch of your choice (&lt;code&gt;&quot;develop&quot;&lt;&#x2F;code&gt; in this case):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;# Simple workflow for deploying static content to GitHub Pages&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; Deploy static docs content to Pages&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;on&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;  # Runs on pushes targeting the default branch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;  push&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;    branches&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;develop&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;  # Allows you to run this workflow manually from the Actions tab&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;  workflow_dispatch&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;permissions&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;  contents&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; read&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;  pages&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; write&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;  id-token&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; write&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;# Allow one concurrent deployment&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;concurrency&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;  group&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;pages&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;  cancel-in-progress&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;  # Single deploy job since we&amp;#39;re just deploying&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;  deploy&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;    environment&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;      name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; github-pages&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;      url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; ${{ steps.deployment.outputs.page_url }}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;    runs-on&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; ubuntu-latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;    steps&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; Checkout&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;        uses&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; actions&#x2F;checkout@v3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; Setup Pages&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;        uses&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; actions&#x2F;configure-pages@v3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt; uses&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; actions-rs&#x2F;cargo@v1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;        with&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;          command&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; doc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; index.html redirect&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;        uses&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;DamianReeves&#x2F;write-file-action@master&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;        with&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;          path&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; .&#x2F;target&#x2F;doc&#x2F;index.html&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;          write-mode&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; overwrite&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;          contents&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt; |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;            &amp;lt;meta http-equiv=&amp;quot;Refresh&amp;quot; content=&amp;quot;0; url=&amp;#39;🚧YOUR_CRATE_NAME🚧&#x2F;index.html&amp;#39;&amp;quot; &#x2F;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; Upload artifact&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;        uses&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; actions&#x2F;upload-pages-artifact@v1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;        with&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;          # Upload docs repository&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;          path&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;#39;.&#x2F;target&#x2F;doc&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; Deploy to GitHub Pages&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;        id&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; deployment&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;        uses&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; actions&#x2F;deploy-pages@v1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Because the documentation is stored in &lt;code&gt;YOUR_CRATE&#x2F;target&#x2F;doc&lt;&#x2F;code&gt; and there&#x27;s no top-level &lt;code&gt;index.html&lt;&#x2F;code&gt;, we need to create one that simply redirects to your crate&#x27;s documentation. That&#x27;s what the &lt;code&gt;DamianReeves&#x2F;write-file-action@master&lt;&#x2F;code&gt; action is for.&lt;&#x2F;p&gt;
&lt;p&gt;GitHub should give you a short url at &lt;code&gt;https:&#x2F;&#x2F;YOUR_ORG_NAME.github.io&#x2F;YOUR_REPO_NAME&lt;&#x2F;code&gt; which will redirect you to some Heroku-style subdomain. You can even limit the visibility to contributors-only.&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s it! Hope you enjoy Rust&#x27;s documentation features as much as I do.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;[&lt;a href=&quot;https:&#x2F;&#x2F;briankung.dev&#x2F;2023&#x2F;05&#x2F;20&#x2F;one-of-my-favorite-rust-features&#x2F;#-0&quot;&gt;0&lt;&#x2F;a&gt;]: Apparently this is all covered in the guide to &quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;cargo&#x2F;reference&#x2F;publishing.html&quot;&gt;Publishing on crates.io&lt;&#x2F;a&gt;&quot;&lt;&#x2F;p&gt;
&lt;p&gt;[&lt;a href=&quot;https:&#x2F;&#x2F;briankung.dev&#x2F;2023&#x2F;05&#x2F;20&#x2F;one-of-my-favorite-rust-features&#x2F;#-1&quot;&gt;1&lt;&#x2F;a&gt;]: There is also Javadoc, Pydoc, and YARD (Ruby) docs for generating documentation.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Public school is a bad deal for us</title>
        <published>2023-03-04T22:25:31+00:00</published>
        <updated>2023-03-04T22:25:31+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2023/03/04/public-school-is-a-bad-deal-for-us/"/>
        <id>https://briankung.dev/2023/03/04/public-school-is-a-bad-deal-for-us/</id>
        
        <content type="html" xml:base="https://briankung.dev/2023/03/04/public-school-is-a-bad-deal-for-us/">&lt;p&gt;&lt;em&gt;Actually, that really understates the problem - we feel that living in the USA is a bad deal for families in general, but for now I&#x27;ll focus specifically on public school and daycare.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;My wife and I were taking a stroll around the neighborhood with our three kids during the week when I realized - there&#x27;s no one else out here. As in, there are no other families enjoying the (at the time) fall weather. Occasionally you would see a caretaker pushing a stroller, or a pair of adults power walking, but we were basically the only nuclear family out on the sidewalks. And we were almost always the only nuclear family we saw on weekdays.&lt;&#x2F;p&gt;
&lt;p&gt;My mind took me to the fact that the fault lines of our society are all determined by fealty to corporate interests. After all, the biggest reason for putting kids in daycare, especially at such young ages, is to be able to work.&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, that triggered this diatribe on the downsides of sending our kids out to daycare or public school. The caveat is that both my wife and I have the privilege to be able to work remotely, support ourselves, and also raise our kids - even if it&#x27;s somewhat hectic at times.&lt;&#x2F;p&gt;
&lt;p&gt;⚠️ To reiterate: this essay is &lt;em&gt;especially&lt;&#x2F;em&gt; true for us because we can work remote with reasonable work-life balances - to the point where we feel like we would prefer to keep the kids home for now. This is not everyone&#x27;s situation, but the downsides I list below for families living in America are, in my opinion, downsides for all.&lt;&#x2F;p&gt;
&lt;p&gt;So let&#x27;s go one by one through reasons why people send their kids to school - &quot;school&quot; meaning daycare on up, starting with the hygiene hypothesis, or how people have interpreted the hygiene hypothesis, anyway. Basically, the idea that sending your kids into the line of fire builds up their immunity against pathogens.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;immunity&quot;&gt;Immunity&lt;&#x2F;h2&gt;
&lt;p&gt;When the pandemic hit, we withdrew our eldest from the school system and began what eventually turned into an ad hoc system for homeschooling.&lt;&#x2F;p&gt;
&lt;p&gt;Now that President Biden has &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.npr.org&#x2F;2022&#x2F;09&#x2F;19&#x2F;1123767437&#x2F;joe-biden-covid-19-pandemic-over&quot;&gt;declared&lt;&#x2F;a&gt; covid &quot;over,&quot; but more to the point that all of our kids are vaccinated against it and we&#x27;re busy with work, we have been considering when and how to get the kids back into the public sphere. That means daycare and school.&lt;&#x2F;p&gt;
&lt;p&gt;Immediately the next thing that happened was a wave of RSV, flu, &lt;em&gt;and&lt;&#x2F;em&gt; covid. If you&#x27;re not a parent or you&#x27;re not familiar with RSV, it&#x27;s called &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.cdc.gov&#x2F;rsv&#x2F;index.html&quot;&gt;Respiratory Synctial Virus&lt;&#x2F;a&gt;, and in my circles it&#x27;s put more kids into the ER than covid has. Here&#x27;s an apocalyptic article on the trio of diseases: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.nytimes.com&#x2F;2022&#x2F;11&#x2F;01&#x2F;science&#x2F;rsv-children-hospitals.html&quot;&gt;US Children’s Hospitals Are Overwhelmed by RSV - The New York Times&lt;&#x2F;a&gt; (note: I would treat &quot;immune debt&quot; as a more questionable idea than the article presents it, which I cover &lt;a href=&quot;https:&#x2F;&#x2F;briankung.dev&#x2F;2023&#x2F;03&#x2F;04&#x2F;public-school-is-a-bad-deal-for-us&#x2F;#immune-debt&quot;&gt;below&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;Like clockwork, parents in our circles had to call off work to take care of their kids. It&#x27;s a miserable experience - oftentimes you have to take care of your children while you yourself require care-taking due to being sick with the same thing. And it&#x27;s almost inevitable if you send young kids to school. Even older kids will share food with each other and swap masks, if they even bother to wear masks.&lt;&#x2F;p&gt;
&lt;p&gt;So how do you protect your kids and yourself if you send your kids into public school? You don&#x27;t. You just accept that you&#x27;ll get sick. That&#x27;s how it was for us before the pandemic. We would be miserable every other week. Isolating from society during the pandemic was hard, but not being sick twice a month was a revelation - one we don&#x27;t want to give up.&lt;&#x2F;p&gt;
&lt;p&gt;What about &quot;building up the kids&#x27; immunity&quot; you ask? Well, we know that herd immunity &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.statnews.com&#x2F;2022&#x2F;03&#x2F;25&#x2F;how-we-got-herd-immunity-wrong&#x2F;&quot;&gt;doesn&#x27;t really work for covid&lt;&#x2F;a&gt;, reinfection after vaccination or illness is &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.news-medical.net&#x2F;news&#x2F;20220809&#x2F;Icelandic-study-suggests-SARS-CoV-2-Omicron-reinfection-more-common-than-previously-thought.aspx&quot;&gt;fairly common&lt;&#x2F;a&gt;, and reinfections &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.forbes.com&#x2F;sites&#x2F;roberthart&#x2F;2022&#x2F;11&#x2F;10&#x2F;covid-reinfections-may-boost-chances-of-death-and-organ-failure-study-finds---and-the-risk-increases-each-time-you-catch-it&#x2F;?sh=57b9102b2b2d&quot;&gt;boost chances of death and organ failure&lt;&#x2F;a&gt;. And while these articles are all about covid, it&#x27;s not too far a leap to guess that other viral diseases might have similar profiles. For instance, RSV immunity &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pubmed.ncbi.nlm.nih.gov&#x2F;2010624&#x2F;&quot;&gt;lasts about 2 months&lt;&#x2F;a&gt;. Measles actually robs the people it infects of immunity &lt;em&gt;from other viruses&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;So - they hygiene hypothesis is one thing. Dirt, bacteria, wind, rain, and sunshine are all fair game for priming a young immune system. But viruses can do some really deep damage - like &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.mdanderson.org&#x2F;publications&#x2F;focused-on-health&#x2F;7-viruses-that-cause-cancer.h17-1592202.html&quot;&gt;cause cancer&lt;&#x2F;a&gt;. If you could really exercise your immune system like you could a muscle everyone would start out licking public school drinking fountains and some would eventually graduate to licking &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Biosafety_level&quot;&gt;BSL&lt;&#x2F;a&gt; 4 door knobs. My point being that there is a limit to the progressive overload that the immune system can take.&lt;&#x2F;p&gt;
&lt;p&gt;Viruses are also often attenuated, or made weaker, by overly &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Virulence&quot;&gt;virulent&lt;&#x2F;a&gt; strains of virus killing their hosts and therefore becoming evolutionary dead ends, whereas weaker strains continue to let their hosts spread the infection. We don&#x27;t have that natural attenuation in the United States because our health care system is really good at two things: keeping you in debt, and keeping you alive. So there is a really high theoretical threshold to a virus keeping itself in check via virulence because the ER will pump you full of steroids, prescribe a raft of antibiotics (just in case), and then mail you exorbitant medical bills for the privilege over the course of the next few years.&lt;&#x2F;p&gt;
&lt;p&gt;And we are breeding these particularly potent viruses in daycares and public schools.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;socialization&quot;&gt;Socialization&lt;&#x2F;h2&gt;
&lt;p&gt;Another factor that people, and even doctors, bring up is that of socialization. As in, if you don&#x27;t send your kids to school, they will grow up to be some sort of Neanderthalic reject, unable to cope with the modernity of the world.&lt;&#x2F;p&gt;
&lt;p&gt;Our kids are mostly too young to be able to tell, but I have my doubts. When we sent our eldest into daycare, she socialized, but it was, ah, how do you say this sensitively...it&#x27;s downright abusive.&lt;&#x2F;p&gt;
&lt;p&gt;Our daughter, Avery, is an endlessly cheery girl, to the point where it&#x27;s detrimental to her own health. Her &quot;best friend&quot; at the time, of which she had many, was a girl named Rylee (sp?) who would show her affection by boxing Avery&#x27;s ears or pinching her upper lip so hard it would draw blood. And that&#x27;s just what we heard about. When we asked the daycare staff about it, they were very apologetic and issued an incident report and did essentially nothing to prevent it from happening again, which it did.&lt;&#x2F;p&gt;
&lt;p&gt;There are never enough teachers, because again the point of a daycare is to make a profit, not to optimize your kids&#x27; well-being, and when they are there, they are powerless to prevent anything. I wouldn&#x27;t be surprised if the parents of a bully are more likely to be bullies themselves, so an educator puts their careers on the line by disciplining bullies, unless the entire administration is willing to go to bat for the teacher. Much cheaper to just find an excuse for the bully&#x27;s behavior.&lt;&#x2F;p&gt;
&lt;p&gt;And if your kid isn&#x27;t one of the bullies to begin with, they might learn to be one. Avery came home from daycare at some point and started kicking her grandfather because &quot;the boys did it.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;Our daughter isn&#x27;t our only point of reference, either. Cici and I both grew up in the US school system. We are familiar with the abuses one can receive from classmates and teachers. And many of our friends&#x27; children have had run-ins with bullies, racists, and racist bullies. Maybe if you&#x27;re white with Aryan features, public school is a breeze for you. But for many people, and especially people of color, &quot;socialization&quot; means getting used to being abused.&lt;&#x2F;p&gt;
&lt;p&gt;Our school system leads to an arms race in bullying, a Lord of the Flies environment where the bullies rule, the bullied grow resentful until they finally strike back. With the easy availability of weapons, it&#x27;s no wonder that the United States is ground zero for school shootings, worldwide.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;education&quot;&gt;Education&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;ve treaded and retreaded this so many times that it&#x27;s a given to me, but I do not believe that children learn better in school, at least early on. Both in personal experience with our eldest and the fact that schools &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.cdc.gov&#x2F;sleep&#x2F;features&#x2F;schools-start-too-early.html&quot;&gt;start too early&lt;&#x2F;a&gt;, disrupting sleeping schedules, or that we wouldn&#x27;t be able to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;briankung.dev&#x2F;2022&#x2F;04&#x2F;13&#x2F;how-and-why-our-kids-are-learning-chinese&#x2F;&quot;&gt;teach our children Chinese&lt;&#x2F;a&gt;, or teach them about the racism that we&#x27;ve faced in various institutions - school included.&lt;&#x2F;p&gt;
&lt;p&gt;📚 Our personal experience with having our eldest study math or Chinese is that, given the right incentives, she can focus for longer periods of time on difficult subjects than she likely would be asked to in school. While we started her out with fun apps for learning math (like &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dragonbox.com&#x2F;products&quot;&gt;DragonBox&lt;&#x2F;a&gt; and later &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.prodigygame.com&#x2F;main-en&#x2F;&quot;&gt;Prodigy&lt;&#x2F;a&gt; games), we&#x27;ve since moved on to more focused study using &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.ixl.com&#x2F;&quot;&gt;IXL&lt;&#x2F;a&gt;, and she&#x27;s done really well. Similarly for Chinese, we started her out on the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.ihuman.com&#x2F;website&#x2F;pc&#x2F;en&#x2F;shizi&#x2F;&quot;&gt;iHuman&lt;&#x2F;a&gt; 洪恩识字 app and then graduated her to reading short fiction and writing messages to her grandparents.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s also consider the effect that the school system has on kids&#x27; outlooks on learning. I think the biggest problem with keeping the kids busy in school is the busy-ness. They have a lot of &lt;em&gt;things&lt;&#x2F;em&gt; to do and not enough time to let their minds wander or get bored and do things just because. It&#x27;s modeled after work.&lt;&#x2F;p&gt;
&lt;p&gt;We consider boredom to be an essential part of learning. This ties into our policy on technology, as well, but essentially outside of a few focused hours of work time, Avery is free to do whatever she wants - except screen time. As a result, she is often bored, and as a result of &lt;em&gt;that&lt;&#x2F;em&gt;, she:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Plays with her siblings&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Crafts using cardboard and knick-knacks around the house&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Does origami&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Plays the piano&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Reads every new fiction book she can get to&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Reads extensively about flowers and succulents&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;We don&#x27;t have to push her to do anything artistic or literary. She just wants to. And, importantly, she has the time to do it.&lt;&#x2F;p&gt;
&lt;p&gt;School busy work is often tedious, uninspiring, and time consuming. Boredom is merely tedious until you find the next thing to get in trouble with.&lt;&#x2F;p&gt;
&lt;p&gt;To be fair, a lot of the downsides are mediated by the kids&#x27; relationships with their parents. School doesn&#x27;t have to be a tedious, boring slog, but it does end up taking freedom away from the kids, by design (otherwise they&#x27;d be interrupting your standups and 1:1&#x27;s).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;just-plain-bad&quot;&gt;Just plain bad&lt;&#x2F;h2&gt;
&lt;p&gt;Forgot to mention a few key elements that play into our decision to keep the kids at home that are just plain bad instead of replies to common reasons to send the kids to school:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;school-shootings-and-active-shooter-drills&quot;&gt;School shootings and active shooter drills&lt;&#x2F;h3&gt;
&lt;p&gt;Despite the fact that it is statistically unlikely for your child to be actually shot in a school shooting, the fact that it&#x27;s likely &lt;em&gt;enough&lt;&#x2F;em&gt; for active shooter drills to be taught in school is terrifying. The drills themselves should be considered traumatizing and the fact that we allow this to happen at all is a damning condemnation of where we are at as a country. And if an active shooter situation ever does happen, it&#x27;s not just the shooting victims who are traumatized, it&#x27;s the entire school. So we view school shootings as likely to affect us and growing more likely with every year, compared to when my wife and I were in school.&lt;&#x2F;p&gt;
&lt;p&gt;Even if the drills themselves &lt;em&gt;weren&#x27;t&lt;&#x2F;em&gt; traumatizing, the things we&#x27;ve heard of the active shooter drills themselves would be hilarious if it weren&#x27;t so serious. For example, our friend&#x27;s kid was given the advice to &quot;zig zag to avoid fire&quot; as if it was a big game of Counter-Strike. That is a great way to incite uncontrollable chaos in a class of kindergartners. &quot;Hide behind your classmates&#x27; bodies and play dead&quot; can be practical, yet horrifying.&lt;&#x2F;p&gt;
&lt;p&gt;These things shouldn&#x27;t happen. Ever. Having to think about school shootings alone makes the US a horrible place to raise a family.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;meal-habits&quot;&gt;Meal habits&lt;&#x2F;h3&gt;
&lt;p&gt;On a less acutely deadly note, children simply don&#x27;t eat well at school, and it is unacceptable to us. My nephew, who is in high school, is given 20 minutes to eat lunch and barely eats more an apple. Younger children don&#x27;t eat, and when they do they do their damnedest to infect each other with the latest and greatest viruses.&lt;&#x2F;p&gt;
&lt;p&gt;At home, we make sure the kids are well fed, even if it takes cajoling, bribing, and presenting different options at the right times. If our eldest is any indicator we will eventually have a bunch of great eaters, but right now it is a game of escalating bribery. It would pain us to no end to send the kids to school with a full lunch box and then have to throw most of it out when they come back. It&#x27;s bad for their health and it&#x27;s food waste.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;In the end, school is a really tough deal for us right now. We&#x27;re still struggling with our eventual reentry into the world and what&#x27;s best for our kids, because while this environment is ideal for them in some ways, it&#x27;s not a typical one, and we don&#x27;t want that to end up stunting their ability to adapt to the world we live in.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Professional Rustacean, 3 months in</title>
        <published>2023-02-17T17:25:20+00:00</published>
        <updated>2023-02-17T17:25:20+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2023/02/17/professional-rustacean-3-months-in/"/>
        <id>https://briankung.dev/2023/02/17/professional-rustacean-3-months-in/</id>
        
        <content type="html" xml:base="https://briankung.dev/2023/02/17/professional-rustacean-3-months-in/">&lt;p&gt;Hi! 👋 I did end up landing that Rust job I was &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;briankung.dev&#x2F;2022&#x2F;08&#x2F;18&#x2F;contributing-to-the-vector-remap-language&#x2F;&quot;&gt;looking for&lt;&#x2F;a&gt;, and I&#x27;ve been wrestling with the Rust programming language now for a good couple of months - not quite 3, if I&#x27;m to be honest, but who&#x27;s counting.&lt;&#x2F;p&gt;
&lt;p&gt;To be honest, I&#x27;m a little bit ambivalent. I think it&#x27;s a great language for a few reasons, but I will be honest in that I am not nearly as productive as I would be in other languages. For context, I&#x27;m using it mostly in web development, where my language and framework of choice is usually Ruby and Rails.&lt;&#x2F;p&gt;
&lt;p&gt;Yes, I am aware of the opinion &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=34835631&quot;&gt;on Hacker News&lt;&#x2F;a&gt; that it&#x27;s a good language for low level use cases, but arguably not the right choice for web development. Then you have comments like &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=34836459&quot;&gt;this one&lt;&#x2F;a&gt; that run counter to that narrative. I have to wonder why Rust seems to work at all levels for some, but not as much for me, but then I only have 2-3 months of experience with the language.&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, these aren&#x27;t meant to be pros or cons, just notes.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;it-s-programmer-catnip&quot;&gt;It&#x27;s programmer catnip&lt;&#x2F;h2&gt;
&lt;p&gt;I would guess that &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.scientificamerican.com&#x2F;article&#x2F;experts-how-does-catnip-work-on-cats&#x2F;&quot;&gt;about 70-80% of programmers&lt;&#x2F;a&gt; love rolling around in it, stuffing our faces in it, and playing with the language features. The reason is pretty simple - we&#x27;re generally technical people, and Rust has the wonderful characteristic of exposing us to all the technicalities underlying the systems we&#x27;re building, but with warning signs.&lt;&#x2F;p&gt;
&lt;p&gt;When I use Rust, I feel like I&#x27;m learning about the underlying systems and models. To take a cheap example, consider Rust&#x27;s &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;runrust.miraheze.org&#x2F;wiki&#x2F;String_Types&quot;&gt;string types&lt;&#x2F;a&gt;. The fact that they are modeled in such a complex way &lt;em&gt;reflects&lt;&#x2F;em&gt; the complexity of string handling in computers. Learning how to use strings in Rust teaches you the difference between strings that are valid UTF-8, operating system strings, C-style strings, and the difference between borrowed and owned strings.&lt;&#x2F;p&gt;
&lt;p&gt;Does it suck? Yes. Is it educational? Also yes. Is it gratifying to eventually understand? Yes.&lt;&#x2F;p&gt;
&lt;p&gt;Learn to use Rust and you&#x27;ll learn about computing. And that&#x27;s a big draw to a lot of programmers, because there&#x27;s a big overlap between programmers and people who, well, like computers.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;type-system-gymnastics&quot;&gt;Type system gymnastics&lt;&#x2F;h2&gt;
&lt;p&gt;In Ruby, where everything is an object, you often perform message passing gymnastics to glue everything together. If it quacks like a duck but you need it to walk like a human, well, you better get the duck quacking to the dog that barks at the human. You can inject anything anywhere, as long as it passes the right messages. It&#x27;s like infinitely interchangeable gears.&lt;&#x2F;p&gt;
&lt;p&gt;This doesn&#x27;t fly in Rust. Rust is not object oriented. Rust is more type oriented than object oriented. Just because two objects have functions with the same name doesn&#x27;t mean that they&#x27;re interchangeable. Things hinge more on whether they are the same type, or can be coaxed into that type, or implement the same trait. So instead of mashing objects together willy nilly, you need to figure out how to get from one type or implementation to another.&lt;&#x2F;p&gt;
&lt;p&gt;In Ruby, you can traverse the world via methods. In Rust, you must traverse the world via the type system. It&#x27;s a different trapeze, but you can still swing it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;productivity-tradeoff&quot;&gt;Productivity tradeoff&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;m way less productive in Rust than I am in Ruby, at least for web development purposes. I am a lot more confident in the quality of the code, though. Oftentimes when I find myself attempting to write unit tests, I write one as a higher level integration test to check that the method I&#x27;m adding exists and behaves, but then any additional tests that I would have written in Ruby to handle edge cases are instead handled by the type system and simply refuse to compile.&lt;&#x2F;p&gt;
&lt;p&gt;That said, I am 2.5 months into this Rust journey and the type system gymnastics can definitely take a toll. But it&#x27;s such potent catnip that I find myself energized to come back to it again and again.&lt;&#x2F;p&gt;
&lt;p&gt;I think that confidence is invisible to business stakeholders, but I suspect that, despite the lower &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Velocity_(software_development)&quot;&gt;initial velocity&lt;&#x2F;a&gt;, there&#x27;s much higher guarantee of quality and maintainability.&lt;&#x2F;p&gt;
&lt;p&gt;First, the Rust compiler probably won&#x27;t stop compiling your application code, at least for any code written in recent times, due to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.rust-lang.org&#x2F;2014&#x2F;10&#x2F;30&#x2F;Stability.html&quot;&gt;Rust&#x27;s stability guarantee&lt;&#x2F;a&gt;. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;rust&#x2F;comments&#x2F;11348jp&#x2F;examples_of_old_ca_100_rust_code_that_still&#x2F;&quot;&gt;Probably&lt;&#x2F;a&gt;. That&#x27;s just not true in Ruby. Breaking changes with no &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;edition-guide&#x2F;editions&#x2F;index.html&quot;&gt;edition system&lt;&#x2F;a&gt; mean that the chronological window for valid code shifts. Ancient code in other languages will bitrot faster than in Rust.&lt;&#x2F;p&gt;
&lt;p&gt;For instance, one of our Ruby code bases dates back to Christmas, Dec 2018 at the earliest, and no longer builds. Meanwhile, from the linked Reddit post above:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;suffix&#x2F;0.2.10&quot;&gt;&lt;code&gt;suffix 0.2.10&lt;&#x2F;code&gt; was published on April 15, 2015&lt;&#x2F;a&gt;, one month &lt;em&gt;before&lt;&#x2F;em&gt; Rust 1.0 came out [and still compiles]&lt;&#x2F;p&gt;
&lt;p&gt;- &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;rust&#x2F;comments&#x2F;11348jp&#x2F;examples_of_old_ca_100_rust_code_that_still&#x2F;&quot;&gt;Examples of old (ca. 1.0.0+) Rust code that still compiles? : rust&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;That said, I&#x27;m still slower to write Rust than I am to write Ruby. Perhaps that&#x27;s due to a lack of familiarity with the language in practice - we&#x27;re measuring a decade or more of experience with Ruby with maybe a few months of professional experience with Rust.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>AI morality</title>
        <published>2022-12-07T21:19:42+00:00</published>
        <updated>2022-12-07T21:19:42+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2022/12/07/ai-morality/"/>
        <id>https://briankung.dev/2022/12/07/ai-morality/</id>
        
        <content type="html" xml:base="https://briankung.dev/2022/12/07/ai-morality/">&lt;p&gt;&lt;em&gt;I cobbled this together from a few comments I&#x27;d made on Facebook - please forgive the lack of coherency.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Is it moral to ask AI art program to create something &quot;in the style of&quot; a living artist?&lt;&#x2F;p&gt;
&lt;p&gt;Is it moral to ask an AI art program to create something in between styles of two artists?&lt;&#x2F;p&gt;
&lt;p&gt;What about three artists? Four?&lt;&#x2F;p&gt;
&lt;p&gt;Stable Diffusion and other AI art bots take this to the nth degree. Just because the number, n, of artists is very high does not mean that it is not immoral to profit off of the work of artists. And remember - there are people who are using these artists&#x27; work to get rich.&lt;&#x2F;p&gt;
&lt;p&gt;Also note that just because this usage of public domain hasn&#x27;t been challenged in the court of law doesn&#x27;t mean it never will be.&lt;&#x2F;p&gt;
&lt;p&gt;I think this is a brand new day for IP law.&lt;&#x2F;p&gt;
&lt;p&gt;And for those who might argue that &quot;impressionism or cubism isn&#x27;t protected by law,&quot; it&#x27;s not so much that the &lt;em&gt;style&lt;&#x2F;em&gt; of art is protected, but that the works made in those styles have been directly and algorithmically derived from artists without their consent. Today it&#x27;s &quot;make a comic in the style of Shen Comix&quot; and tomorrow it&#x27;ll be &quot;make me a video of Jacob saying he hates tacos&quot; - or worse. But whether it&#x27;s people&#x27;s public images, the works they put online, or data that&#x27;s scraped, I think the law will need to catch up in protecting the data that we produce and the impact of its derivations on us.&lt;&#x2F;p&gt;
&lt;p&gt;Another way to think of this problem is that intellectual property is supposed to protect the rights - and properties - of the inventors. In the case of AI produced properties, who is the inventor of the work? The person who wrote the prompt? The AI that responded? The owners of the data that it was trained on? Or the author of the algorithm that produced the AI model?&lt;&#x2F;p&gt;
&lt;p&gt;Either way, I think it&#x27;s a valid argument to make that the owners of the training data should have a say in this.&lt;&#x2F;p&gt;
&lt;p&gt;I want to acknowledge that AI is really exciting and out of everyone in my circles, I&#x27;ve probably used it the most. I&#x27;ve used Stable Diffusion on my Mac to produce images and I&#x27;ve also used ChatGPT to produce code, or as a pair programming partner. The technology is really exciting and magical.&lt;&#x2F;p&gt;
&lt;p&gt;But I think we all underestimate what we&#x27;re owed here. Researchers have trained these bots on our data - likely our posts on Facebook, my public blog and open source code have all been used to train various AI. Media artists may have the most skin in the game here, with the amount of labor and the sheer amount of data they produce.&lt;&#x2F;p&gt;
&lt;p&gt;This is a data issue, but ultimately it is a labor issue. All the data we produce - and we produce it constantly simply through the labor of existing - should be our intellectual property and should be protected under the law. These kinds of AI wouldn&#x27;t be possible in jurisdictions with strong data privacy laws like the EU and California.&lt;&#x2F;p&gt;
&lt;p&gt;And it shouldn&#x27;t be, because the ill gotten gains of those data violations end up, ultimately, in the hands of, like, three people who have been chosen mostly by privilege, racism, and heritage to amass wealth.&lt;&#x2F;p&gt;
&lt;p&gt;Now if there was an AI model that was trained using *only* fully consenting users&#x27; data† and that model was free for everyone to use everywhere, I&#x27;d have a lot less to complain about. However, Midjourney, Lensa, ChatGPT, et al. are not that. Everyone should read Karla Ortiz&#x27;s post about the moral issues surrounding the image databases that were used to train Stability AI, Midjourney, and even Google: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;threadreaderapp.com&#x2F;thread&#x2F;1593723972314882048.html&quot;&gt;https:&#x2F;&#x2F;threadreaderapp.com&#x2F;thread&#x2F;1593723972314882048.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Fun with Gleam</title>
        <published>2022-12-03T17:42:28+00:00</published>
        <updated>2022-12-03T17:42:28+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2022/12/03/fun-with-gleam/"/>
        <id>https://briankung.dev/2022/12/03/fun-with-gleam/</id>
        
        <content type="html" xml:base="https://briankung.dev/2022/12/03/fun-with-gleam/">&lt;p&gt;This&#x27;ll be a short blog post, but Gleam (v0.25.0) is an Erlang OTP language, akin to Elixir (in fact, recently added full compatibility with Elixir packages). It&#x27;s been &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;ad1405bc7b49daff73e8f40f84445ba2&quot;&gt;fun so far&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I think the error messages are great and the functional style language is a lot of fun to wrap my brain around. I have had some clerical issues trying to find resources for things as simple as opening files and referencing type variants, but the discord channel has been really helpful.&lt;&#x2F;p&gt;
&lt;p&gt;For reference, opening files is apparently done through an Erlang bridge. First add &lt;code&gt;gleam_erlang&lt;&#x2F;code&gt; to your project:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; gleam add gleam_erlang&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then use it like so:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;gleam&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; gleam&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;erlang&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;file&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;pub fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; main&lt;&#x2F;span&gt;&lt;span&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  file.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;read&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;.&#x2F;input&#x2F;two.txt&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Thanks to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;markholmes.org&#x2F;&quot;&gt;Mark Holmes&lt;&#x2F;a&gt; for assisting me on the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;discord.gg&#x2F;Fm8Pwmy&quot;&gt;Gleam Discord&lt;&#x2F;a&gt; with that tip!&lt;&#x2F;p&gt;
&lt;p&gt;And referencing type constructors, or what look suspiciously like Rust&#x27;s Enum variants, after import can be confusing.&lt;&#x2F;p&gt;
&lt;p&gt;If you have a custom type like so:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;gleam&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;&#x2F;&#x2F; src&#x2F;animal.gleam&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;&#x2F;&#x2F; 👇 this is a &amp;quot;type&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;pub type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; Move&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;  &#x2F;&#x2F; 👇 these are &amp;quot;type constructors&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;  Rock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;  Paper&lt;&#x2F;span&gt;&lt;span&gt;         &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;  Scissors&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And I was trying to reference it elsewhere like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;gleam&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; move.{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Move&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;pub fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; main&lt;&#x2F;span&gt;&lt;span&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  move.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;compare&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Move&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Rock&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Move&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Paper&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You will get an error. That is because types and type constructors both importable at the same level. So you *can* import &lt;code&gt;Move&lt;&#x2F;code&gt; as the umbrella type for &lt;code&gt;Rock&lt;&#x2F;code&gt;, &lt;code&gt;Paper&lt;&#x2F;code&gt;, and &lt;code&gt;Scissors&lt;&#x2F;code&gt;, but if you&#x27;re just going to use &lt;code&gt;Rock&lt;&#x2F;code&gt; and &lt;code&gt;Paper&lt;&#x2F;code&gt;, then you can do so like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;gleam&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; move.{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Rock&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Paper&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;pub fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; main&lt;&#x2F;span&gt;&lt;span&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  move.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;compare&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Rock&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Paper&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The other thing I was hoping for was to be able to destructure function arguments, but alas twas not to be. I had:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;gleam&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;list.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;map&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;font-style: italic;&quot;&gt;game: &lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;List&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Move&lt;&#x2F;span&gt;&lt;span&gt;)) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;  let&lt;&#x2F;span&gt;&lt;span&gt; [a, b] &lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; game&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  move.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;compare&lt;&#x2F;span&gt;&lt;span&gt;(a, b)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;...and I really wanted to be able to get rid of the &lt;code&gt;let&lt;&#x2F;code&gt; statement like so:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;gleam&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;list.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;map&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span&gt;([a, b]) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  move.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;compare&lt;&#x2F;span&gt;&lt;span&gt;(a, b)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Which is unfortunately not currently possible.&lt;&#x2F;p&gt;
&lt;p&gt;I would say these are really minor, though. The benefit of using Gleam is that you can depend on types when you want with an Elixir-like paradigm. The error messages are great, at one point reminding me when I was trying to use &lt;code&gt;result.is_ok()&lt;&#x2F;code&gt; that Gleam is not an object oriented language, and that I would probably be better off using &lt;code&gt;Result.is_ok(result)&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Pipes are also great. I feel like I&#x27;m making Super Mario Maker with all the pipes I&#x27;m putting in. For instance, you could write the above &lt;code&gt;Result&lt;&#x2F;code&gt; code like so:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;gleam&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;result&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #179299;&quot;&gt;|&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; Result&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;is_ok&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Gleam is smart enough to use the result of the last computation as the first argument in the next one. But if you want, you can also reference the last result as an underscore in case you need to pass it in to a different positional argument:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;gleam&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;100&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #179299;&quot;&gt;|&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; int.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;random&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There are a bunch of other cool things about the language but I have to go because my children are hangrily destroying things. Oh! The LSP server and automatic todo annotations are awesome. Okay, gotta go.&lt;&#x2F;p&gt;
&lt;p&gt;Have a terrifying AI generated image:&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;images&#x2F;000000_866775386_kdpmpp2m15_ps7.5_an_8-bit_pixel_of_mario_jumping_through_silicon_motherboard_pipes_for_the_hero_image_of_a_blog_post_generated.jpg&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;images&#x2F;000000_866775386_kdpmpp2m15_ps7.5_an_8-bit_pixel_of_mario_jumping_through_silicon_motherboard_pipes_for_the_hero_image_of_a_blog_post_generated.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;figcaption&gt;
&lt;p&gt;Stable diffusion prompt: an 8-bit pixel of Mario jumping through silicon motherboard pipes for the hero image of a blog post&lt;&#x2F;p&gt;
&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;PIPES&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>On interviewing</title>
        <published>2022-11-14T22:14:40+00:00</published>
        <updated>2022-11-14T22:14:40+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2022/11/14/on-interviewing/"/>
        <id>https://briankung.dev/2022/11/14/on-interviewing/</id>
        
        <content type="html" xml:base="https://briankung.dev/2022/11/14/on-interviewing/">&lt;p&gt;Many people (millennials, at least) have been trained to kiss ass when we&#x27;re interviewing, to basically &quot;fake it til you make it.&quot; This can take several forms:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;People pleasing&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Professional ambition&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Sacrificing personal boundaries&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Many of these behaviors actually hurt candidates during interviews, especially marginalized candidates and young people early in their careers.&lt;&#x2F;p&gt;
&lt;p&gt;These are behaviors that reduce the signal around whether the candidate will fit with the team. The interviewer&#x27;s confidence in your person is one of the most important qualities in an interview, arguably beyond your qualifications for the role. If your resume is a dead ringer for the role but the interviewer can&#x27;t be sure whether you’re actually who you say you are, what your motivations are, or what your personality is like, it&#x27;s going to be a hard sell.&lt;&#x2F;p&gt;
&lt;p&gt;And for the most part, hiring managers can figure out when someone is being authentic, has a genuine interest in the position, and is trying to figure out if the position matches their needs. It&#x27;s easier to ascertain whether there&#x27;s real alignment when candidates are open about their own requirements.&lt;&#x2F;p&gt;
&lt;p&gt;On the other hand, a candidate who is trying to say the right things in order to get the job is harder to get quality information about. They might actually be qualified, but it&#x27;s harder to tell because the candidate is trying to guess what the interviewer wants. When this is obvious it&#x27;s damaging, and for many early career applicants it&#x27;s fairly obvious. Behaviors like showering the company with faint praise, dissembling, and never disagreeing, pushing back, or showing vulnerability.&lt;&#x2F;p&gt;
&lt;p&gt;Interviewers must also make judgments beyond the candidate&#x27;s basic competency. Will they stick around? Suddenly drop out of contact? What&#x27;s their work style? It can be difficult to read between the lines if they&#x27;re putting up a facade. This once again lowers the confidence the interviewer can have in their decision making process.&lt;&#x2F;p&gt;
&lt;p&gt;For their part, candidates should also ask questions about their own requirements, but generally younger people won&#x27;t because they haven&#x27;t established work-life boundaries. So they people please instead, or talk about how they are ambitious and eager to learn and grow, work overtime or without pay. Let&#x27;s talk about each of those in turn:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;People pleasing - lowers the confidence in the interviewee being entirely truthful&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Professional ambition - the candidate might outgrow the position which might not be a benefit to the company&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Sacrificing personal boundaries - could telegraph unprofessionalism, disorganization, or a bad culture fit. Abusive employers might take this as a good sign, though.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Any of these might disqualify the candidate from consideration which would exacerbate their lack of professional experience.&lt;&#x2F;p&gt;
&lt;p&gt;And we can&#x27;t forget that the power dynamic will almost always be tilted in favor of the employer. So I don&#x27;t blame candidates for choosing not to be vulnerable, especially if they&#x27;re early in their careers or from a marginalized background. And here&#x27;s really where the crux of the matter lies - most of the power in the USA is concentrated in capital, in the business&#x27;s hands. As much as everyone deserves to have a living wage (and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Universal_basic_income&quot;&gt;universal basic income&lt;&#x2F;a&gt;!), ultimately everyone is forced to produce under capitalism.&lt;&#x2F;p&gt;
&lt;p&gt;What does that mean for interviewees? Well, it means that people early in their careers, people from marginalized backgrounds, people who are economically disadvantaged, and many others will appear less palatable than those who were already born into privilege. They do not fit in, or they can&#x27;t perform authenticity, or don&#x27;t seem &quot;professional.&quot; This extends to the first impression - the resume. While a resume may seem like a culmination of one&#x27;s own efforts, it can also be seen as a list of privileges that have been afforded to you, a snowball of privilege that helps roll up the next opportunity.&lt;&#x2F;p&gt;
&lt;p&gt;And then the problem compounds because they will have less life and professional experiences to draw from for the next interview, or they will have experiences that others deem unsuitable for the same reasons. Think of someone suing an employer for being racist and then being seen by future employers as the problem instead of their previous employer.&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, I&#x27;m a bit far afield, but this all came from several conversations with my wife, who has been hiring for her team and finding it really hard to find people who engage in an honest conversation, especially young candidates. We believe that every candidate - every person - deserves a living wage, but she can&#x27;t hire them all. And we see a lot of young people making the same mistakes that we did - people pleasing and playing up strengths that are irrelevant to the job description.&lt;&#x2F;p&gt;
&lt;p&gt;For instance, sometimes ambition is valued. In my wife&#x27;s case, and we suspect in many other cases, it is not. Hiring managers don&#x27;t want a candidate to be everything their company could ever want now or in the future - they want someone to fill a present need, and oftentimes that need will not go away, so if a candidate telegraphs that they will outgrow the position it&#x27;s potentially disqualifying.&lt;&#x2F;p&gt;
&lt;p&gt;(Side note, as RPG players, my wife and I shared this misconception about employment early in our careers, too - that you can never outgrow a position. If you&#x27;re level 100 of course you can do level 1 work! But employers disagree; you can definitely be overqualified because you&#x27;re a flight risk or odd goods.)&lt;&#x2F;p&gt;
&lt;p&gt;So something that my wife and I both landed on in our careers is that it&#x27;s easier to be authentic about our own needs and wants and push back on what we perceive as the business&#x27;s requirements. If there&#x27;s a lack of mutual respect or alignment, then it&#x27;s a quick way to find out that it&#x27;s not a good fit. However, we have the advantages of being in the middle of our careers in highly demanded fields.&lt;&#x2F;p&gt;
&lt;p&gt;I suspect that, for many, it starts early. Children&#x27;s team sports, for example. I think social knowledge and the urge to contribute on an organizational level can get a good start here. Another one is just exposure to professional settings. The push and pull of an interview, not just as a rubric for the employer, but also for the employee, requires a level of comfort that doesn&#x27;t come to many people naturally without practice.&lt;&#x2F;p&gt;
&lt;p&gt;(Incidentally, these types of things are coded as very white to me. The most white-adjacent people of color I know are all very into sports, and it&#x27;s probably an advantage in your career because you learn how to socialize and organize for a group of people. Just another quiet advantage that white people take for granted, like 529s and legacy admission.)&lt;&#x2F;p&gt;
&lt;p&gt;But that said, is it possible to teach confidence and authenticity to other job seekers, especially younger folks?&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Getting into tech</title>
        <published>2022-10-25T15:36:43+00:00</published>
        <updated>2022-10-25T15:36:43+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2022/10/25/getting-into-tech/"/>
        <id>https://briankung.dev/2022/10/25/getting-into-tech/</id>
        
        <content type="html" xml:base="https://briankung.dev/2022/10/25/getting-into-tech/">&lt;p&gt;When I graduated from college with a degree in East Asian Languages and Culture from the University of Illinois at Urbana-Champaign in 2011 (one year late), I had no idea what I was going to do. To compare with my fellow EALC majors, one had started a restaurant, one got into horseback riding, and another was a brand ambassador. So basically, I was at square one.&lt;&#x2F;p&gt;
&lt;p&gt;A few things from my background contributed to me landing in software, however:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;🕹 I was a computer enthusiast from a young age, whether that was begging my uncle to start up Commander Keen on his computer, being the first kid on the block with cable internet, or the first with a high end graphics card (all hail the Radeon 9700 Pro). I read MaximumPC to drool over the latest game graphics and that introduced me to Slashdot, where I learned about up and coming startups and also comment karma systems.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;💻 I picked up Learn HTML in 24 Hours at some point and wrote some basic websites - mostly unordered lists. Then I grew bored. As a result, my websites to this day are still mostly unordered lists and that&#x27;s why &lt;em&gt;this&lt;&#x2F;em&gt; website runs on Wordpress.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;🐍 I also picked up a book on learning Python in high school, probably mostly because snakes are &lt;em&gt;cool&lt;&#x2F;em&gt; and installing software had this mythological status. Installing software was fun for the sake of enabling new things. That includes updates to software. I no longer have this fascination, but it&#x27;s a nostalgic feeling. Oh, and Python? I did a few simple math problems in the REPL, like &lt;code&gt;1 + 1&lt;&#x2F;code&gt;, but lost interest. This was the same as my TI-83, but without the graphs! I was almost disgusted at how useless it was. Little did I know. My impression of Python remained, however. Sorry Pythonistas.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;👨‍🎓 I started my college career at a community college. When I transferred to the University of Illinois at Urbana-Champaign, I tried a semester in a humanities major, actually the one I would end up graduating with, and decided I wanted more of a challenge. I chose Electrical Engineering because I had heard it was the hardest major on campus, and that turned out to be true enough to switch back &lt;em&gt;out&lt;&#x2F;em&gt; of the major after a semester, but not before getting a B in ECE 190, where I would learn how circuits built up to logic boards and how to program in LC-3 assembly and a bit of C. This would actually help my intuition a lot later on. And for what it&#x27;s worth, I didn&#x27;t consider going into computer science because it was for &quot;smart people.&quot;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;📚 During a summer break in college after I had broken up with my first girlfriend, I decided I needed some time for my soul to heal. I thought reading some Great Literature™ would be a good way to do that, so I picked up a few books by someone I had heard of. As it turns out, I somehow had a brain fart and mixed up the American essayist David Sedaris with the marketer Seth Godin and ended up reading a lot of marketing books, instead. But by that time I had forgotten why I wanted the books in the first place, so I was happy to read, anyway. This led me to the very repetitive world of business books and, by extension, repetitive business ideas.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Yet, even after all of this, I didn&#x27;t really consider making tech a career until after college. I was more interested in get rich quick and 4 Hour Workweek schemes. After graduating from college, I spent a few months chasing these fruitless ideas until I found an article called &quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20190701201856&#x2F;https:&#x2F;&#x2F;lifehacker.com&#x2F;how-to-build-a-web-application-from-scratch-with-no-exp-5336113&quot;&gt;How to Build a Web Application from Scratch with No Experience&lt;&#x2F;a&gt;.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;briankung&#x2F;status&#x2F;780814870392532992&quot;&gt;https:&#x2F;&#x2F;twitter.com&#x2F;briankung&#x2F;status&#x2F;780814870392532992&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I was excited to build a web application, run a startup, and learn career skills along the way. There was good alignment. Ironically I still haven&#x27;t really built any of the web applications I&#x27;ve wanted, personally, but it got me looking into Ruby and Ruby on Rails.&lt;&#x2F;p&gt;
&lt;p&gt;At this point, I was definitely 80% interested in startups and 20% interested in programming. But there was some foreshadowing that those ratios might flip. One of the earlier schemes I had come up with was to write books and self publish them. Except that instead of writing, I spent most of the time coming up with a &lt;em&gt;sick website&lt;&#x2F;em&gt; that looked like a literal bookshelf to sell my nonexistent books from. Did the ecommerce work? No, and what the hell is ecommerce? But the website was &lt;em&gt;cool&lt;&#x2F;em&gt; and that&#x27;s what mattered.&lt;&#x2F;p&gt;
&lt;p&gt;After some self-study, I got an internship at the Chicago Teachers Pension Fund (CTPF) as an intern. I had a lot of chutzpah, because I was emailing people to ask if I could be an intern even if there were no listings for internships. My go-to line was &quot;I&#x27;m not the senior software engineer you&#x27;re looking for, but...&quot; and then I&#x27;d go into my pitch about how motivated I was. Eventually it worked. Honestly, I wasn&#x27;t given a lot of guidance - and in fact there was none to give, since CTPF wasn&#x27;t a Rails shop - but I felt like I was on the way, and I&#x27;m grateful for the opportunity.&lt;&#x2F;p&gt;
&lt;p&gt;Nearly simultaneously, I found out about a coding bootcamp called Code Academy in Chicago which would eventually rename itself Starter League. I followed a lot of their students, who were highly recommended to write blog posts, and got very hyped up about the entire &quot;code as literacy&quot; movement and bootcamps in general, so I was very excited to apply. They gave me a short window of time to accept and I had to crowdfund around $3000 in order to attend. I have a lot of my friends and family to thank for supporting me, though it would weigh on me later. I hung up my hat at the CTPF and went to attend the bootcamp.&lt;&#x2F;p&gt;
&lt;p&gt;It was less like the bootcamps of today, which are full-time, and more like an paid club, since it was at most something like 6 hours of instruction per week, but I really liked the people and the environment. We operated out of the newly constructed 1871, a coworking space in the Chicago Merchandise Mart. After being one of the star students, mostly because I had done a good amount of self-study beforehand, I realized I was helping people out more than I was being helped. I was also fielding questions from other people in my life and the greater Chicago ecosystem asking about my impressions of the course and I realized...&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20130328112015&#x2F;http:&#x2F;&#x2F;www.callmekung.com&#x2F;2013&#x2F;03&#x2F;i-cant-recommend-attending-starter-league&#x2F;&quot;&gt;I just couldn&#x27;t recommend it.&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I get a high off of buying things when they&#x27;re on sale - I don&#x27;t do it often, but if the discount is large enough, it&#x27;s hard for me to resist. It&#x27;s part of my immigrant background. I&#x27;m used to saving and scrounging, whether that&#x27;s hoarding takeout containers and plastic bags, or buying in bulk when there are flash sales on groceries. Code Academy was not a good deal, and I had to come clean about it.&lt;&#x2F;p&gt;
&lt;p&gt;On the other hand, I was really drinking the kool-aid when it came to startup hustle culture. There&#x27;s no doubt that that kind of energy and dedication helped me get into the profession, even though I&#x27;ve renounced it since then. I was applying everywhere, meeting tons of people, and overall ⚡️ &lt;em&gt;killing it, bro&lt;&#x2F;em&gt; ⚡️.&lt;&#x2F;p&gt;
&lt;p&gt;👉 Fun side story: I showed up to an interview in shorts and flip flops. I also bombed the technical interview, which had a lot of CSS questions, which I shrugged at and said, &quot;I would have to look that up&quot; multiple times. You have to understand, I have almost zero test anxiety, so showing up to interviews half assed is a full ass for me. They very earnestly told me that maybe I should take these things more seriously, wear better clothes, and come more prepared. I very solemnly agreed to their faces and then changed absolutely nothing about myself.&lt;&#x2F;p&gt;
&lt;p&gt;Some of the most fun I had was just hanging out and with the troublemakers Jared Steffes, Agam Patel, and Chris Ingebrigtsen on Matador, an investment advice startup that was all sweat equity, as far as I could tell - I don&#x27;t think anyone was being paid a salary. I was technically &quot;working&quot; for Jared, but really the draw was just being part of a gang of jokesters. I got to put it on my resume and build out some image upload functionality. One time I actually needed the money and asked Jared to cut me a check and it looked like he was drawing the money from his arteries. I don&#x27;t remember what I needed the money for, but I remember that I was very amused at his pained expression.&lt;&#x2F;p&gt;
&lt;p&gt;Still, I consider my first real step on the path to being a software engineer to be my job at Aggrego, which was a digital &quot;skunkworks&quot; embedded in the Chicago Sun-Times which was funded by a madman. The editorial staff hated us because we were well-funded and an annoying distraction, and the plan of throwing money at the paper until it became a successful digital property didn&#x27;t really pan out, but I did meet some great people like Nikola Ranguelov, Erick Arias, Shannon Carey, and Dave Willkomm, who was a great mentor to me.&lt;&#x2F;p&gt;
&lt;p&gt;Aggrego was the most &quot;strict&quot; Agile workplace I&#x27;ve been at since, with velocity tracking, team pointing, burndown charts, retrospectives, product managers, visual and UX designers, and more. It was a great learning experience. There were some downsides, like the madman in charge who full-out screamed at someone with the door open while I was pair programming with an intern - and no, that intern did not want to stay with us. I myself was screamed at when I forgot to show up for a midnight deploy. But I also got to feed my friends takeout when the company agreed to host &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.eulersprint.org&#x2F;&quot;&gt;Project Euler Sprint&lt;&#x2F;a&gt;, I got a ridiculously high salary for an entry level job at the time ($75,000 in 2012). I almost bought a house!&lt;&#x2F;p&gt;
&lt;p&gt;And then of course I quit the moment I got bored.†&lt;&#x2F;p&gt;
&lt;p&gt;† ...so I could pursue my own startup.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Contributing to the Vector Remap Language</title>
        <published>2022-08-18T21:56:54+00:00</published>
        <updated>2022-08-18T21:56:54+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2022/08/18/contributing-to-the-vector-remap-language/"/>
        <id>https://briankung.dev/2022/08/18/contributing-to-the-vector-remap-language/</id>
        
        <content type="html" xml:base="https://briankung.dev/2022/08/18/contributing-to-the-vector-remap-language/">&lt;p&gt;I&#x27;ve been looking for a job doing Rust development and one of the places I applied to was Vector, a DataDog acquisition in the observability space. Observability is one of those terms I had yet to encounter seriously before starting this search, so for the uninitiated:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;...observability is the ability to measure a system’s current state based on the data it generates, such as logs, metrics, and traces.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.dynatrace.com&#x2F;news&#x2F;blog&#x2F;what-is-observability-2&#x2F;&quot;&gt;- What is observability?&lt;&#x2F;a&gt; | Dynatrace&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Now, I didn&#x27;t get hired at Vector, but I did discover their product, which is an open source, programmable &#x2F; configurable data pipeline tool. I&#x27;ll leave the explanation to them:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Vector is a high-performance observability data pipeline that enables you to collect, transform, and route all of your logs and metrics.&lt;&#x2F;p&gt;
&lt;p&gt;- &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;vector.dev&#x2F;docs&#x2F;about&#x2F;what-is-vector&#x2F;&quot;&gt;Vector documentation&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vectordotdev&#x2F;vector&#x2F;&quot;&gt;vectordotdev&#x2F;vector&lt;&#x2F;a&gt; repo was several hundred thousand lines of Rust code. This was probably slightly more complex than my 100 loc CLI app. I was intrigued - would Rust&#x27;s type system hinder me? Would the compile times grind down my productivity? I wanted to see what it was like to do development on a real production application and get some additional Rust development under my belt, for personal and professional reasons. Thankfully, Vector being open source, I could do that.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Regarding contributing to open source: as someone who regularly finds employment in the tech industry, and is married to a working spouse with health insurance, I have a certain degree of privilege that affords me the time to contribute to open source. It&#x27;s important to acknowledge that open source is not a meritocracy and lack of open source contributions should not be considered a flaw in a candidate&#x27;s application. Working mothers, new entrants to the field, and people from under-represented groups have statistically less free time to make these kinds of contributions. Furthermore, as Ashe Dryden states in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.ashedryden.com&#x2F;blog&#x2F;the-ethics-of-unpaid-labor-and-the-oss-community#apprenticeships&quot;&gt;&quot;The Ethics of Unpaid Labor and the OSS Community&quot;&lt;&#x2F;a&gt;, there are &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.ashedryden.com&#x2F;blog&#x2F;the-ethics-of-unpaid-labor-and-the-oss-community#apprenticeships&quot;&gt;a few ways&lt;&#x2F;a&gt; we can work to level the playing field for under-represented groups.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;I got in touch with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jszwedko&quot;&gt;Jesse&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;fuchsnj&quot;&gt;Nathan&lt;&#x2F;a&gt; on the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;chat.vector.dev&#x2F;&quot;&gt;Vector Discord channel&lt;&#x2F;a&gt; via a former coworker (thanks Nathan Prime!). Jesse was kind enough to tell me about the company and the observability space over Zoom as well as point me to a few good first issues I could tackle on the vector repo and Nathan reviewed my code several times over the course of the month.&lt;&#x2F;p&gt;
&lt;p&gt;I decided to tackle &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vectordotdev&#x2F;vector&#x2F;issues&#x2F;13329&quot;&gt;issue #13329&lt;&#x2F;a&gt;, adding a &lt;code&gt;chunk&lt;&#x2F;code&gt; method to the Vector Remap Language (VRL) stdlib.&lt;&#x2F;p&gt;
&lt;p&gt;Vector is essentially an ETL (Extract-Transform-Load) platform for shuffling data from one place to another (or in Vector lingo, from Sources to Sinks), and VRL is the domain language for transforming the data. If, for instance, you need to split, parse, or otherwise massage your logs before sending them to your data warehouse, VRL is the language a Vector user would do it in.&lt;&#x2F;p&gt;
&lt;p&gt;The rationale for the &lt;code&gt;chunks&lt;&#x2F;code&gt; method was that a Vector user had to send the transformed data to an API with a limitation of 1MB and wanted to be able to split the data into 1MB chunks.&lt;&#x2F;p&gt;
&lt;p&gt;I read a great article by the founder of HashiCorp, Mitchell Hashimoto, called &quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;mitchellh.com&#x2F;writing&#x2F;contributing-to-complex-projects&quot;&gt;Contributing to Complex Projects&lt;&#x2F;a&gt;&quot; which was very insightful. The key ideas for me were to &quot;become a user of the project&quot; and &quot;learn down, trace up.&quot; The first is self explanatory. The second one was about tracing the execution path of a command down to the leaf nodes and then tracing the operations back up until you understand the entire path.&lt;&#x2F;p&gt;
&lt;p&gt;I highly recommend reading Hashimoto&#x27;s article, but not for the purposes of this blog post because I unfortunately disregarded its advice. I just dove right in and tried to grep my way out. I won&#x27;t elaborate that much on the journey, but little things like knowing that working on VRL means implementing a &lt;em&gt;programming language&lt;&#x2F;em&gt; might have helped me grok things a bit faster.&lt;&#x2F;p&gt;
&lt;p&gt;Adding the &lt;code&gt;chunks()&lt;&#x2F;code&gt; method is basically adding a global method to the standard library that Vector users can use in their VRL scripts. We can separate my pull request to the VRL stdlib into a few different pieces:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Adding the method to the default features. I needed to do this first in order to get the unit tests to actually run:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vectordotdev&#x2F;vector&#x2F;pull&#x2F;13794&#x2F;files#diff-80267028c9325bf0206270a8f0a4ff32b3e97cd544e847bfaa3d5dc9840e994f&quot;&gt;lib&#x2F;vrl&#x2F;stdlib&#x2F;Cargo.toml&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vectordotdev&#x2F;vector&#x2F;pull&#x2F;13794&#x2F;files#diff-0e4a5b858d4f321b6db75f693291423714011fbfb6fab0a3fe1967f1f71fbe66&quot;&gt;lib&#x2F;vrl&#x2F;stdlib&#x2F;src&#x2F;lib.rs&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Implementing the function itself:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vectordotdev&#x2F;vector&#x2F;pull&#x2F;13794&#x2F;files#diff-2166716f04399fa4177d788683336e029a5e889207341eca092761ff5a585e1dR5-R22&quot;&gt;fn chunks&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vectordotdev&#x2F;vector&#x2F;pull&#x2F;13794&#x2F;files#diff-2166716f04399fa4177d788683336e029a5e889207341eca092761ff5a585e1dR121-R144&quot;&gt;associated unit tests&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Implementing the function metadata and various checks:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The VRL function&#x27;s &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vectordotdev&#x2F;vector&#x2F;pull&#x2F;13794&#x2F;files#diff-2166716f04399fa4177d788683336e029a5e889207341eca092761ff5a585e1dR32-R45&quot;&gt;parameters&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vectordotdev&#x2F;vector&#x2F;pull&#x2F;13794&#x2F;files#diff-2166716f04399fa4177d788683336e029a5e889207341eca092761ff5a585e1dR62-R97&quot;&gt;VRL compile time errors&lt;&#x2F;a&gt; and its &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;%5Blib&#x2F;vrl&#x2F;tests&#x2F;tests&#x2F;functions&#x2F;chunks_chunk_size_at_least_1.vrl%5D(https:&#x2F;&#x2F;github.com&#x2F;vectordotdev&#x2F;vector&#x2F;pull&#x2F;13794&#x2F;files#diff-c06e11439418bd09b6bca3fd53b84bd43d52c6ef166a4471402675deb001c84b)&quot;&gt;associated test&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vectordotdev&#x2F;vector&#x2F;pull&#x2F;13794&#x2F;files#diff-2166716f04399fa4177d788683336e029a5e889207341eca092761ff5a585e1dR113-R117&quot;&gt;VRL fallibility constraints&lt;&#x2F;a&gt; and its &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;%5Blib&#x2F;vrl&#x2F;tests&#x2F;tests&#x2F;functions&#x2F;chunks_fallible_given_expression.vrl%5D(https:&#x2F;&#x2F;github.com&#x2F;vectordotdev&#x2F;vector&#x2F;pull&#x2F;13794&#x2F;files#diff-40d2174476a8fb7e0213860b226bd007f3f1f7028ae682374abfb0fdf173d536)&quot;&gt;associated test&lt;&#x2F;a&gt; - more on fallibility later&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Finally, documentation:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vectordotdev&#x2F;vector&#x2F;pull&#x2F;13794&#x2F;files#diff-2166716f04399fa4177d788683336e029a5e889207341eca092761ff5a585e1dR47-R60&quot;&gt;Examples&lt;&#x2F;a&gt;, which are essentially doctests&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vectordotdev&#x2F;vector&#x2F;pull&#x2F;13794&#x2F;files#diff-2168de40756007ecadeec59ccc750348cae2db3ca66d061c7dcbf3ce791e15cb&quot;&gt;chunks.cue&lt;&#x2F;a&gt;, which is a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;cuelang.org&#x2F;&quot;&gt;CUE lang&lt;&#x2F;a&gt; file for specifying Vector&#x27;s gorgeous documentation&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;It all came together a lot faster when Nathan &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vectordotdev&#x2F;vector&#x2F;pull&#x2F;13794#discussion_r940608620&quot;&gt;suggested that I try out the REPL&lt;&#x2F;a&gt; with &lt;code&gt;cargo run vrl&lt;&#x2F;code&gt;, then I could try to use the function in the terminal. It was a lot easier to understand - hence Hashimoto&#x27;s advice to become a user of the project. Just goes to show that you can lead a horse to water, but you can&#x27;t make it drink.&lt;&#x2F;p&gt;
&lt;p&gt;(Drinking is following directions. I&#x27;m the horse.)&lt;&#x2F;p&gt;
&lt;p&gt;Now, one of the reasons VRL is neat is because it makes fallibility a first class concept. If a function is determined to be fallible at compile time, you have to handle the error, much like &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;stable&#x2F;nightly-rustc&#x2F;rustc_lint&#x2F;unused&#x2F;static.UNUSED_MUST_USE.html&quot;&gt;unused_must_use&lt;&#x2F;a&gt; in Rust. Somewhat confusingly, functions are not inherently fallible or infallible. The determination is made during the compilation process and depends on the inputs.&lt;&#x2F;p&gt;
&lt;p&gt;So for &lt;code&gt;chunks()&lt;&#x2F;code&gt;, which takes two parameters, a string and a &lt;code&gt;chunk_size&lt;&#x2F;code&gt; in bytes, we decided to make it infallible if the &lt;code&gt;chunk_size&lt;&#x2F;code&gt; parameter was a literal integer, and fallible otherwise, for instance it it was a method call.&lt;&#x2F;p&gt;
&lt;p&gt;So if you have a vrl program chunking a string into single byte chunks like so:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;result = chunks(&amp;quot;abcd&amp;quot;, 1)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot;, &amp;quot;d&amp;quot;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is infallible. The &lt;code&gt;chunk_size&lt;&#x2F;code&gt; of &lt;code&gt;1&lt;&#x2F;code&gt; is a literal integer, so the compilation process does not force the user to handle any errors.&lt;&#x2F;p&gt;
&lt;p&gt;Meanwhile, if you want a dynamic &lt;code&gt;chunk_size&lt;&#x2F;code&gt;, you get an error:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;result = chunks(&amp;quot;abcd&amp;quot;, int!(floor(4.1)))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;error[E103]: unhandled fallible assignment&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ┌─ :1:10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  │&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1 │ result = chunks(&amp;quot;abcd&amp;quot;, int!(floor(4.1)))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  │ -------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  │ │        │&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  │ │        this expression is fallible&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  │ │        update the expression to be infallible&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  │ or change this to an infallible assignment:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  │ result, err = chunks(&amp;quot;abcd&amp;quot;, int(floor(4.1)))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  │&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  = see documentation about error handling at https:&#x2F;&#x2F;errors.vrl.dev&#x2F;#handling&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  = learn more about error code 103 at https:&#x2F;&#x2F;errors.vrl.dev&#x2F;103&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  = see language documentation at https:&#x2F;&#x2F;vrl.dev&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  = try your code in the VRL REPL, learn more at https:&#x2F;&#x2F;vrl.dev&#x2F;examples&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To account for the fallibility, you must handle the error. Like Go, VRL has multiple return values, one for the value and one for the error:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;result, err = chunks(&amp;quot;abcd&amp;quot;, int!(floor(4.1)))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;quot;function call error for \&amp;quot;chunks\&amp;quot; at (14:46): function call error for \&amp;quot;int\&amp;quot; at (29:45): expected integer, got float&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There&#x27;s currently a bit of tension between fallibility and compilation errors. For instance, we almost decided to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vectordotdev&#x2F;vector&#x2F;pull&#x2F;13794#discussion_r944875231&quot;&gt;make invalid inputs for &lt;code&gt;chunk_size&lt;&#x2F;code&gt; fallible&lt;&#x2F;a&gt;, but went with making them compile time errors, instead. That way the user wouldn&#x27;t have to handle the fallibility and then additionally handle the error during runtime, the program just wouldn&#x27;t compile in the first place.&lt;&#x2F;p&gt;
&lt;p&gt;From a language ergonomics perspective, while I still enjoyed using Rust, the compile times did become painful. Compiling a debug version of vector from scratch took 7 minutes and 30 seconds. I later switched to using the mold linker and it went down to 6 minutes, but it was still disruptive. Meanwhile, a full release mode compile would take 14 minutes on my Core i9 iMac. Thankfully, incremental compiles were much quicker.&lt;&#x2F;p&gt;
&lt;p&gt;I also haven&#x27;t dug down into the root cause of the issue yet, but rust-analyzer did not do so well in this code base:&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;images&#x2F;image-3.png&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;images&#x2F;image-3.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;figcaption&gt;
&lt;p&gt;Not the most useful type hints&lt;&#x2F;p&gt;
&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;Between the unknown types and rust-analyzer spinning up the CPU fan on every change and establishing a file lock on the package cache that would block the compiler, I got off to a rough start.&lt;&#x2F;p&gt;
&lt;p&gt;For context, I didn&#x27;t really &lt;em&gt;get&lt;&#x2F;em&gt; Rust until I had rust-analyzer working. I had tried Rust a few times before without it or an IDE, and I felt like I was boxing the compiler blindfolded. I&#x27;d make a move only to be hammered with a novel type of compiler error with no real way to resolve it. Rust-analyzer&#x27;s in-editor hints and tight feedback loop really helped me understand the language. So rust-analyzer being less useful and even slowing down compilation was a big difference to my usual Rust workflow. I even turned off rust-analyzer for a bit to see if I got better and faster feedback from the compiler. Ultimately, I turned it back on, but it was painful getting used to the slow analysis and compilation speeds.&lt;&#x2F;p&gt;
&lt;p&gt;Ultimately, though, I still enjoyed programming in Rust - how can I get this chain of &lt;code&gt;if let&lt;&#x2F;code&gt; statements to look more readable without actually having &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;rust-lang.github.io&#x2F;rfcs&#x2F;2497-if-let-chains.html&quot;&gt;if-let chains&lt;&#x2F;a&gt;? How can I best use the type system to enforce the boundaries on valid inputs? Also the vector test harness, documentation system, and just working on a programming language (with its own type system) were very cool experiences.&lt;&#x2F;p&gt;
&lt;p&gt;So in conclusion, I just need a faster computer 😛&lt;&#x2F;p&gt;
&lt;p&gt;If this article inspired you to take a look at the Vector repo, Jesse also pointed me in the direction of this issue which is fairly similar to adding &lt;code&gt;chunks()&lt;&#x2F;code&gt; to the stdlib:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vectordotdev&#x2F;vector&#x2F;issues&#x2F;13104&quot;&gt;Add `zip` function to VRL · Issue #13104 · vectordotdev&#x2F;vector&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It should follow the same broad strokes as &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vectordotdev&#x2F;vector&#x2F;pull&#x2F;13794&quot;&gt;adding &lt;code&gt;chunks()&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;. Take a look and happy coding!&lt;&#x2F;p&gt;
&lt;h4 id=&quot;additional-resources&quot;&gt;Additional Resources&lt;&#x2F;h4&gt;
&lt;p&gt;In no particularly useful order:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;chat.vector.dev&#x2F;&quot;&gt;Vector Discord Channel&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;vector.dev&#x2F;community&#x2F;&quot;&gt;Community | Vector&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vectordotdev&#x2F;vector&#x2F;pull&#x2F;13794&quot;&gt;feat(vrl): Adds `chunks` function by briankung · Pull Request #13794 · vectordotdev&#x2F;vector&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vectordotdev&#x2F;vector&#x2F;issues&#x2F;13329&quot;&gt;Add `chunk` function to split up text into multiple pieces by size · Issue #13329 · vectordotdev&#x2F;vector&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vectordotdev&#x2F;vector&#x2F;issues&#x2F;13104&quot;&gt;Add `zip` function to VRL · Issue #13104 · vectordotdev&#x2F;vector&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;d3rwan.github.io&#x2F;d3rwan-blog&#x2F;posts&#x2F;discovering-vector&quot;&gt;Discovering Vector (2020)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;vector.dev&#x2F;blog&#x2F;vector-remap-language&#x2F;&quot;&gt;Vector Remap Language | Vector&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.ashedryden.com&#x2F;blog&#x2F;the-ethics-of-unpaid-labor-and-the-oss-community#apprenticeships&quot;&gt;&lt;&#x2F;a&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.ashedryden.com&#x2F;blog&#x2F;the-ethics-of-unpaid-labor-and-the-oss-community#apprenticeships&quot;&gt;The Ethics of Unpaid Labor and the OSS Community | ashe dryden&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Oxidization: Nested hashes</title>
        <published>2022-07-10T12:41:02+00:00</published>
        <updated>2022-07-10T12:41:02+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2022/07/10/oxidization-nested-hashes/"/>
        <id>https://briankung.dev/2022/07/10/oxidization-nested-hashes/</id>
        
        <content type="html" xml:base="https://briankung.dev/2022/07/10/oxidization-nested-hashes/">&lt;p&gt;This might be an idiosyncrasy of mine, but I tend to use &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ruby-doc.org&#x2F;core&#x2F;Hash.html&quot;&gt;hashes&lt;&#x2F;a&gt; a lot in Ruby. For instance, recently I was working on a code challenge involving ordering food. There were different categories of courses (breakfast, lunch, and dinner) and different categories of foods (main dish, side dish, etc.), and you need both in order to resolve the final dish name (e.g. &lt;code&gt;lunch + side dish = &quot;banchan&quot;&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;In Ruby, I would have just used nested hashes. Something like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;menu&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D20F39;&quot;&gt;  breakfast&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;: { ... },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D20F39;&quot;&gt;  lunch&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;: { ... },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D20F39;&quot;&gt;  dinner&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D20F39;&quot;&gt;    main_dish&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;bulgogi&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D20F39;&quot;&gt;    side_dish&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;banchan&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D20F39;&quot;&gt;    drink&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;boricha&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;...and I would use it like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;# What&amp;#39;s for dinner? 🤔&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;menu&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;[:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D20F39;&quot;&gt;dinner&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;][:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D20F39;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;#=&amp;gt; &amp;quot;bulgogi&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I struggled with implementing the same pattern in Rust using HashMaps and Enums. First, the enums:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;#&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Debug&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; Eq&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; PartialEq&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; Hash&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;pub enum&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; Course&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;    Breakfast&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;    Lunch&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;    Dinner&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;#&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Debug&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; Eq&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; PartialEq&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; Hash&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;pub enum&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; Dish&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;    Main&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;    Side&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;    Drink&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Enums have a few advantages over using Ruby symbols as keys in the hashmap. You get IDE and compiler help using enums, whereas in Ruby if you misspell a symbol like, for instance, &lt;code&gt;:dinnner&lt;&#x2F;code&gt;, the code will continue to run, it&#x27;ll just explode somewhere down the line as a runtime error. Rust, on the other hand, will complain during compilation if you spell your variant as &lt;code&gt;Course::Dinnner&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Next to create the nested hashmap:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;use&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt; std&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;collections&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;HashMap&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; menu&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; HashMap&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;([&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;    (&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;        Course&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Breakfast&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;        HashMap&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;([&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;            (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;Dish&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Main&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;米粥&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;            (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;Dish&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Side&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;肉松&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;            (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Dish&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Drink&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;菊花茶&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;        ]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;    ),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;    &#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; item&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; menu&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #179299;&quot;&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;Course&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Breakfast&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #179299;&quot;&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #179299;&quot;&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;Dish&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Main&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #179299;&quot;&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;However, this led to a disagreement with the compiler because &lt;code&gt;item&lt;&#x2F;code&gt; in this case is a reference to a reference. Its type is &lt;code&gt;&amp;amp;&amp;amp;str&lt;&#x2F;code&gt;, which was incompatible with the rest of my function signatures (&lt;code&gt;&amp;amp;str&lt;&#x2F;code&gt;), and I couldn&#x27;t dereference it for some reason (unfortunately lost to an uncommitted rendition of code). I also wanted &lt;code&gt;menu&lt;&#x2F;code&gt; to be a global static constant that I can &lt;code&gt;use&lt;&#x2F;code&gt; elsewhere, which involved using &lt;code&gt;once_cell&lt;&#x2F;code&gt;, and it was just getting overly complicated.&lt;&#x2F;p&gt;
&lt;p&gt;All this led to a rethinking of the problem. I had two keys and wanted to resolve a label for each combination thereof. The HashMap was an implementation detail. Thankfully, I realized Rust had what I need to do resolution of an arbitrary number and type of keys - pattern matching!&lt;&#x2F;p&gt;
&lt;p&gt;Instead of complicated nested hashmaps, I could have a function &lt;code&gt;get_item()&lt;&#x2F;code&gt; that is just a function that matches on &lt;code&gt;Course&lt;&#x2F;code&gt; and &lt;code&gt;Dish&lt;&#x2F;code&gt; and returns a &lt;code&gt;&amp;amp;str&lt;&#x2F;code&gt;. Since it&#x27;s a function, it&#x27;s easy to import in other modules. Since it uses pattern matching, it enforces matches, so adding different &lt;code&gt;Courses&lt;&#x2F;code&gt; and &lt;code&gt;Dishes&lt;&#x2F;code&gt; (which I did) results in compiler warnings which helped me shore up the code. Using a built in meant no more importing &lt;code&gt;HashMap&lt;&#x2F;code&gt; and no more chains of &lt;code&gt;get()&lt;&#x2F;code&gt; and &lt;code&gt;unwrap()&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; get_item&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;&quot;&gt;course&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Course&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;&quot;&gt; dish&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Dish&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; -&amp;gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;static&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; str&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;    match&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;course&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; dish&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;        (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Course&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Breakfast&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; Dish&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Main&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;Oatmeal&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;        (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Course&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Lunch&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; Dish&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Main&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;Fried Rice&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;        (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Course&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Dinner&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; Dish&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Main&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;Curry&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;        &#x2F;&#x2F;  ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; item&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; get_item&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;Course&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Breakfast&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;Dish&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Main&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It worked out quite nicely and made me rethink my use of nested hashes, particularly in Rust but also in Ruby, given the recent addition of native pattern matching:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;menu&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D20F39;&quot;&gt;  dinner&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D20F39;&quot;&gt;    main&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;fried rice&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D20F39;&quot;&gt;    side&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;green beans&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D20F39;&quot;&gt;    drink&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;tea&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;menu &lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;in&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D20F39;&quot;&gt;  dinner&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D20F39;&quot;&gt;    main&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; main&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D20F39;&quot;&gt;    side&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; side&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D20F39;&quot;&gt;    drink&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; drink&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;puts&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;Today we will be eating &lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;#{&lt;&#x2F;span&gt;&lt;span&gt;main&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; with a side of &lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;#{&lt;&#x2F;span&gt;&lt;span&gt;side&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; and &lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;#{&lt;&#x2F;span&gt;&lt;span&gt;drink&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;.&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;# run.rb:9: warning: One-line pattern matching is experimental, and the behavior may change in future versions of Ruby!&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;Today&lt;&#x2F;span&gt;&lt;span&gt; we will be eating fried rice with a side of green beans &lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;and&lt;&#x2F;span&gt;&lt;span&gt; tea&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Neat! One less abuse of nested hashes. Though in Ruby it&#x27;s noticeably less ergonomic to use pattern matching than it is in Rust, so I may stick with nested hashes for this particular use case in Ruby.&lt;&#x2F;p&gt;
&lt;p&gt;You can find all the Rust code for this post in this playground link: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;play.rust-lang.org&#x2F;?version=stable&amp;amp;mode=debug&amp;amp;edition=2021&amp;amp;gist=03ddd0d98364d7a886decbf08d15ed96&quot;&gt;https:&#x2F;&#x2F;play.rust-lang.org&#x2F;?version=stable&amp;amp;mode=debug&amp;amp;edition=2021&amp;amp;gist=03ddd0d98364d7a886decbf08d15ed96&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Rust advocacy at a medium-sized startup</title>
        <published>2022-06-14T12:10:11+00:00</published>
        <updated>2022-06-14T12:10:11+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2022/06/14/rust-advocacy-at-a-medium-sized-startup/"/>
        <id>https://briankung.dev/2022/06/14/rust-advocacy-at-a-medium-sized-startup/</id>
        
        <content type="html" xml:base="https://briankung.dev/2022/06/14/rust-advocacy-at-a-medium-sized-startup/">&lt;p&gt;At Hologram, I loved getting to sign into work Slack and share knowledge with fellow software engineers of all experience levels. There were about 40 engineers in a company closing in on 200 employees.&lt;&#x2F;p&gt;
&lt;p&gt;Meanwhile, the biggest change in my career as a software engineer recently has been learning Rust, which I&#x27;ve been calling a &quot;compiler-guided tour to systems programming.&quot; For me, it has been that and more - I accidentally fell in love with Rust&#x27;s well-crafted APIs, its high assurance qualities, and its community of like-minded and diverse Rustaceans.&lt;&#x2F;p&gt;
&lt;p&gt;I still kept quiet about it because I thought it was irrelevant to our current stack. I also thought that my job as a software engineer was primarily to write code. I hadn&#x27;t considered that organizational initiatives were a natural extension of a software engineer&#x27;s - or more to the point, any employee&#x27;s - role.&lt;&#x2F;p&gt;
&lt;p&gt;That lasted until my coworker Doug unleashed the floodgates by inviting me to pitch Rust in one of the company&#x27;s weekly &quot;Backend Guild&quot; video calls (thanks, Doug! 👋). I can&#x27;t remember what I said at the moment, but I tried to quickly and concisely sum up the aspects of Rust that appealed to me. It must have sounded at least somewhat compelling, though, because someone encouraged us to work on a spike and some proof of concepts, to which I responded by impulsively creating a Slack channel dedicated for what would become the Rust spike initiative.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;images&#x2F;ikj0dtd2q1f70pjtxzejahfajh0lkkcdtnuxmwt8dl0.jpg&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;images&#x2F;ikj0dtd2q1f70pjtxzejahfajh0lkkcdtnuxmwt8dl0.jpg&quot; alt=&quot;A technicolor logo with (I think) 1980s styling proclaiming &amp;quot;Rust Evangelism Strike Force&amp;quot;&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;em&gt;Rust Evangelism Strike Force, coming soon to a company near you!&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;Hologram had &quot;Flex Fridays&quot; in which no meetings were scheduled and you could work in a more self-directed way. Flex Fridays became a flurry of Rust-based initiatives for me, including onboarding people interested in Rust onto the ecosystem and walking them through some of the highlights, writing proof of concept code, and writing documentation - so much documentation. Everything became documentation - the merge requests (MRs are PRs in GitLab parlance), Backend Guild presentations, and one-on-one screensharing sessions were all captured and labeled in Notion to build what I hoped would become a library of Hologram-specific resources for onboarding on to the Rust ecosystem.&lt;&#x2F;p&gt;
&lt;p&gt;Alas, it was not to be. So here are my hopes and dreams, as well as some of the obstacles we met along the way.&lt;&#x2F;p&gt;
&lt;p&gt;I will preface the rest of this post by saying that it is not quantitative by any means. I would have loved to show a histogram of lines of Rust code in production or numbers of developers onboarded, but I never got that far before the company laid off 40% of staff, myself included.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-not-go&quot;&gt;&quot;Why not Go?&quot;&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;images&#x2F;1-ifpd_htdik9u6h68szgnua.png&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;images&#x2F;1-ifpd_htdik9u6h68szgnua.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The issue of whether or not to use Go instead of Rust seems inevitable in any organization. I personally have not used Go in any professional capacity, so my authority on the topic is limited. I will say that, from what I&#x27;ve heard of it, I would likely be more excited to learn and use Go than, for example, Python.&lt;&#x2F;p&gt;
&lt;p&gt;(Sorry Python folks, it&#x27;s close enough to Ruby to give me an uncanny valley effect and I also don&#x27;t want to evaluate which of the many dependency management systems that have sprung up will work the best for me.)&lt;&#x2F;p&gt;
&lt;p&gt;Here are the good things I&#x27;ve heard about Go:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Straightforward language and syntax&lt;&#x2F;li&gt;
&lt;li&gt;Fast compile times&lt;&#x2F;li&gt;
&lt;li&gt;&quot;Batteries included&quot; for web development&lt;&#x2F;li&gt;
&lt;li&gt;Concurrency primitives included&lt;&#x2F;li&gt;
&lt;li&gt;Extremely good performance out of the box&lt;&#x2F;li&gt;
&lt;li&gt;Cross-platform compilation&lt;&#x2F;li&gt;
&lt;li&gt;Statically typed&lt;&#x2F;li&gt;
&lt;li&gt;Compiles down to binaries&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I &lt;em&gt;absolutely&lt;&#x2F;em&gt; did not want this to turn into a language flame war, but unfortunately there&#x27;s something about either the closeness of the release dates of the two languages or their mutual reputations as &quot;systems&quot; programming languages that brings them into contrast with each other. I still don&#x27;t want to talk about either language in the framework of &quot;Go vs. Rust,&quot; so I&#x27;ll talk about the context that directly lead to that comparison, instead.&lt;&#x2F;p&gt;
&lt;p&gt;Shortly before I had joined Hologram, there was an official decision made in the engineering department to adopt two more languages: Go and Typescript. Naturally, when we started talking about adding yet another language, comparisons with Go came up, though in retrospect, it&#x27;s a bit puzzling why Typescript was largely left out of that conversation.&lt;&#x2F;p&gt;
&lt;p&gt;When I started to join Rust advocacy efforts, Doug and I were counseled to know our &quot;opponent&quot; (Go) inside and out, to position Rust as being better than Go, and to really make a business savvy case for Rust. I took this advice to heart, but I also felt that something was off.&lt;&#x2F;p&gt;
&lt;p&gt;I didn&#x27;t want to talk about Go because it&#x27;s simply not what I was passionate about. I also didn&#x27;t want to put down Go users in the company. I just wanted to extol the benefits of Rust and see if anyone was interested in trying it out.&lt;&#x2F;p&gt;
&lt;p&gt;Which brings me to my next point. I thought at first that I had to convince The Company to add it to The Stack™. In actual fact, I had two broad categories of stakeholders to convince, not one Company.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;stakeholder-1-the-business&quot;&gt;Stakeholder #1: The Business&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;images&#x2F;the-lego-movie-lord-business-1-dragged.jpg&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;images&#x2F;the-lego-movie-lord-business-1-dragged.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The Business wants to know why we should invest engineering time into another technology. The Business is about Return on Investment (ROI), and The Business will make do with what we have in order to get things done on time and under budget. The Business will make nuanced arguments about balancing tech debt versus expansion.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m not disparaging business interests - it&#x27;s important to understand, and it&#x27;s part of why any of us are even employed. In fact, one of the biggest lessons I learned from Hologram is how every engineer can focus on &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.effectiveengineer.com&#x2F;&quot;&gt;leverage&lt;&#x2F;a&gt; in order to have the biggest positive impacts on business.&lt;&#x2F;p&gt;
&lt;p&gt;I had a few ideas on how to convince The Business that Rust was worth investing in.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;bug-case-studies&quot;&gt;Bug case studies&lt;&#x2F;h3&gt;
&lt;p&gt;I kept an eye out fixes for bugs that would have been entirely prevented or greatly mitigated in a Rust ecosystem. All of the ones I can remember (invalid array accesses, null return value, empty set checks) would have been caught by returning Rust&#x27;s &lt;code&gt;Option&lt;&#x2F;code&gt; variants for operations.&lt;&#x2F;p&gt;
&lt;p&gt;Then I estimated how much time it took each developer to find and fix these bugs. Developer time translates into money, and these types of bugs were costing a pretty penny. There were two particularly bad weeks where using Rust would have saved a combined 3 weeks worth of developer time. Whether or not they caused any customer-facing issues is also worth noting.&lt;&#x2F;p&gt;
&lt;p&gt;I made sure to write the case studies up, including what happened, how it impacted engineering time, and how writing such bugs would have been impossible or unidiomatic in Rust.&lt;&#x2F;p&gt;
&lt;p&gt;I presented the case studies during a Backend Guild video call and filed the recording away for later reference.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-case-against-go&quot;&gt;The case against Go&lt;&#x2F;h3&gt;
&lt;p&gt;We were challenged to provide a &lt;em&gt;gap analysis&lt;&#x2F;em&gt; for using Rust over Go. I&#x27;ll go into more detail about why I didn&#x27;t like that framing in a separate section, but to sum up in bullet points, I said:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Error handling in Go is optional and not ergonomic&lt;&#x2F;li&gt;
&lt;li&gt;Nils and other issues can slip by Go&#x27;s type system&lt;&#x2F;li&gt;
&lt;li&gt;Rust&#x27;s platform support means that it can be deployed to anywhere from embedded systems to backend web servers&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I read a lot about Go experiences, like these:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;typesanitizer.com&#x2F;blog&#x2F;go-experience-report.html&quot;&gt;Experience Report: 6 months of Go&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;eng.uber.com&#x2F;data-race-patterns-in-go&#x2F;&quot;&gt;Data Race Patterns in Go&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fasterthanli.me&#x2F;articles&#x2F;lies-we-tell-ourselves-to-keep-using-golang&quot;&gt;Lies we tell ourselves to keep using Golang&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I also made sure to connect Rust&#x27;s benefits over Go with the Engineering department&#x27;s started charter values, like how we generally end up going all in for the difficult, more widely applicable technologies, and how we needed to be business savvy - and squashing bugs before they reach customers is business savvy, especially for an infrastructure company like Hologram!&lt;&#x2F;p&gt;
&lt;p&gt;Yet, it made me sad to look up articles on the language just to, in effect, bash it. I&#x27;m not generally in the business of discouraging people from coding, regardless of what their favorite programming language was. If I were, I don&#x27;t think I would have been working on a legacy PHP code base, myself.&lt;&#x2F;p&gt;
&lt;p&gt;Which brings me to the second category of stakeholders who we needed to convince.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;stakeholder-2-the-engineers&quot;&gt;Stakeholder #2: The Engineers&lt;&#x2F;h2&gt;
&lt;figure&gt;
&lt;p&gt;[![Image of a comic with a vertical column containing two panels. In the top panel, an interviewer holding a notebook asks a spectacled male-presenting person &quot;Why is it important to learn Rust&quot; with &quot;learn Rust&quot; having clearly been edited into the image in place of the original text. The interviewee responds &quot;Oh! It has future applications in propulsion energy creation, data transmission, you name it!&quot;&lt;&#x2F;p&gt;
&lt;div&gt;&lt;&#x2F;div&gt;
In the bottom panel, the same interviewer asks the same question, &quot;Why is it important to learn Rust?&quot; and the interviewee, a disheveled male-presenting person with unshaven facial hair responds &quot;Because it&#x27;s fucking AWESOME.&quot;
&lt;div&gt;&lt;&#x2F;div&gt;
The original comic is here: https:&#x2F;&#x2F;www.smbc-comics.com&#x2F;index.php?db=comics&amp;id=2088#comic](&#x2F;assets&#x2F;images&#x2F;20101209-1.gif)](&#x2F;assets&#x2F;images&#x2F;20101209-1.gif)
&lt;figcaption&gt;
&lt;p&gt;&lt;em&gt;Apologies to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.smbc-comics.com&#x2F;index.php?db=comics&amp;amp;id=2088#comic&quot;&gt;Saturday Morning Breakfast Cereal&lt;&#x2F;a&gt; for my hack job&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;In a perfectly rational world, we would all make perfectly rational decisions for ourselves and for the business. These decisions would be carefully weighed until the optimal time and then executed.&lt;&#x2F;p&gt;
&lt;p&gt;But that&#x27;s not how humans work. For one, we all have different priorities. There was the engineering manager who was constantly pushing us to write more documentation. There was devops, who wrote a Go CLI tool to orchestrate pipeline tasks. There was the billing department, which I was on, which put out fires necessary to earning the trust of our customers and their wallets. And there were plenty of engineers who just wanted to go along their days and get things done.&lt;&#x2F;p&gt;
&lt;p&gt;Ultimately, it was these folks who we had to convince. In retrospect, while the business had been officially convinced of the use of Go and Typescript through our decision making processes, the proof, as they say, is in the pudding, and engineers were still writing Javascript and PHP. Their minds may have been made, but their hearts hadn&#x27;t been won.&lt;&#x2F;p&gt;
&lt;p&gt;This was also where, in my opinion, the real difference was made. If we won people&#x27;s hearts, the business case for the language would be made, as all the engineers would want to write Rust, anyway.&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s how I had been planning to win my fellow colleagues over to the dark side:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;personalized-onboarding&quot;&gt;Personalized onboarding&lt;&#x2F;h3&gt;
&lt;p&gt;One of the first things I offered to do was to use our Flex Fridays to onboard people to the new language. It entailed getting a working Rust toolchain up and running and maybe a brief tour of high level language features.&lt;&#x2F;p&gt;
&lt;p&gt;I tried to remember to ask if we could record each session, both for later publication and to see if there were common aspects of onboarding that were problematic. I viewed it as an exercise in customer development, Lean Startup style, as much as an active tutorial.&lt;&#x2F;p&gt;
&lt;p&gt;We did a few of these with people from different backgrounds. One principal engineer with Swift experience compared it to guard lets and other features from Swift. Another engineer found the tooling and ecosystem quite fascinating. And a QA team lead had a lot of fun in our introduction to Rust&#x27;s built-in testing capabilities.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Goals:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Get people over the &quot;getting started&quot; hump&lt;&#x2F;li&gt;
&lt;li&gt;Give high level overview of Rust toolchain features&lt;&#x2F;li&gt;
&lt;li&gt;Bolster documentation with videos&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Metrics:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Number of engineers onboarded: 4&lt;&#x2F;li&gt;
&lt;li&gt;Videos added to documentation: 2&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;proof-of-concepts&quot;&gt;Proof of concepts&lt;&#x2F;h3&gt;
&lt;p&gt;In our use of the term proof of concept, it was less about feasibility studies and more about small code spikes to disseminate learning. To that end, I wrote one proof of concept myself, a cross-platform (Unixes + Windows!) hosts file editor for local development, and contributed to another proof of concept that Doug had started involving DNS.&lt;&#x2F;p&gt;
&lt;p&gt;For both of these, I posted MRs to the Rust slack channel so that everyone could get context. And in the MRs themselves, I went into great detail on the Rust features I was using and why, like &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;stable&#x2F;book&#x2F;ch05-01-defining-structs.html#creating-instances-from-other-instances-with-struct-update-syntax&quot;&gt;Struct Update Syntax&lt;&#x2F;a&gt;, or &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;rust-by-example&#x2F;meta&#x2F;doc.html#doc-comments&quot;&gt;doc comments&lt;&#x2F;a&gt;. Of course, in a production code base with shared context around the language and ecosystem, these explanations would be overly long winded and superfluous. But since our deliverable for these proof of concepts was education, it was appropriate to bloviate a little.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Goals:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Write proof of concepts&lt;&#x2F;li&gt;
&lt;li&gt;Submit code changes for review by non-Rust users&lt;&#x2F;li&gt;
&lt;li&gt;Assess feasibility of using Rust&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Metrics:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Proof of concepts written: 2&lt;&#x2F;li&gt;
&lt;li&gt;Merge requests: 6&lt;&#x2F;li&gt;
&lt;li&gt;Merge requests with extra details: 3&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;presentations&quot;&gt;Presentations&lt;&#x2F;h3&gt;
&lt;p&gt;As I mentioned before, we had a Backend Guild video call every week. I like public speaking, so I used the opportunity to talk about Rust when I had something to talk about.&lt;&#x2F;p&gt;
&lt;p&gt;One of the engineering managers mentioned that she needed better documentation, so I whipped up a quick demonstration of Rust doc comments and doc tests. It helps that documentation is a first class citizen in the Rust ecosystem, so it was easy to do so on the fly. It was a demonstration of the built in documentation, how doc comments get included in the by the doc builder, and how the doc tests are executed and run as code.&lt;&#x2F;p&gt;
&lt;p&gt;I also presented an argument for Rust, the language as a whole, with the main points being the documentation, safety (in terms of impact of bugs on the business), and community. I think Rust&#x27;s diverse and inclusive community (and therefore steering parties via teams and work groups) is perhaps one of its biggest strengths, which manifests itself in a very nuanced, safe, and comprehensive language.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Goals:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Introduce the general engineering department to Rust and specific Rust features&lt;&#x2F;li&gt;
&lt;li&gt;Keep engineering updated on Rust spike initiatives&lt;&#x2F;li&gt;
&lt;li&gt;Add videos to documentation&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Metrics:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Rust talks given: 3&lt;&#x2F;li&gt;
&lt;li&gt;Recordings made: 3&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;documentation&quot;&gt;Documentation&lt;&#x2F;h3&gt;
&lt;p&gt;Because communication and education were key to the Rust spike initiative, documentation was key. I wrote a homepage on our Notion documents entitled &quot;Rust Spike 🦀&quot; which housed all of the above:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Simple getting started guides&lt;&#x2F;li&gt;
&lt;li&gt;Links to proof of concepts&lt;&#x2F;li&gt;
&lt;li&gt;Onboarding and presentation videos&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Additionally, I started an &lt;code&gt;#eng_spike_rust&lt;&#x2F;code&gt; Slack channel which we casually posted news and MRs to.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;on-metrics&quot;&gt;On metrics&lt;&#x2F;h3&gt;
&lt;p&gt;I would have loved to have better metrics of engagement rather than just results, and I hope that someone takes up the mantle and introduces those metrics in my absence. But in an ideal scenario where Rust is officially added to the stack, we would have been able to track better metrics for Rust uptake (depending on goals):&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Proportion of Rust code to legacy code&lt;&#x2F;li&gt;
&lt;li&gt;Proportion of new code bases written in Rust&lt;&#x2F;li&gt;
&lt;li&gt;Performance and maintenance in Rust vs non-Rust code
&lt;ul&gt;
&lt;li&gt;Bug rates&lt;&#x2F;li&gt;
&lt;li&gt;Uptime&lt;&#x2F;li&gt;
&lt;li&gt;Incident rates&lt;&#x2F;li&gt;
&lt;li&gt;Performance&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Usability
&lt;ul&gt;
&lt;li&gt;Number of authors of Rust code&lt;&#x2F;li&gt;
&lt;li&gt;Time to first contribution&lt;&#x2F;li&gt;
&lt;li&gt;Satisfaction surveys&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;...and these are just a first pass at what would hopefully be useful metrics. We would likely need to redo based on what ends up being useful to measure.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;I think company-wide goals and metrics were one place where, if the Go initiative at the company had been stronger, there wouldn&#x27;t have been as much of a vacuum for another language to be considered for general use. Several teams thriving on using Go for their purposes would have made it harder for an arguably marginally better language to shine. Instead, the language stayed siloed in a single repository owned by one team, and the rest of the backend engineers were either stuck on PHP or starting out on Python. In this environment, Rust had a chance, so we made a case for it.&lt;&#x2F;p&gt;
&lt;p&gt;The success of a new language at a company is about the uptake by the individual contributors, and that is a campaign that&#x27;s best made one engineer at a time. That was my starting point, but it would be foolish to leave the business out of the calculus, so I&#x27;m grateful to have been pushed to make a business case for the language as well.&lt;&#x2F;p&gt;
&lt;p&gt;In the end, my time at the company came to a close before I could see the Rust initiative to any sort of fruition, but I&#x27;m grateful that Hologram had that kind of openness to engineer initiatives. It allowed me to learn a lot about advocacy and organizational change.&lt;&#x2F;p&gt;
&lt;p&gt;...even so, I hope to land somewhere that already uses Rust for my next job!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Why PHP is not for me</title>
        <published>2022-06-11T02:46:41+00:00</published>
        <updated>2022-06-11T02:46:41+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2022/06/11/php-is-not-for-me/"/>
        <id>https://briankung.dev/2022/06/11/php-is-not-for-me/</id>
        
        <content type="html" xml:base="https://briankung.dev/2022/06/11/php-is-not-for-me/">&lt;p&gt;So most recently I was employed at Hologram and was therefore too busy to write. Not anymore - I was one of the employees laid off from Hologram recently.&lt;&#x2F;p&gt;
&lt;p&gt;While at Hologram, I worked mostly in PHP, which was something I actually dreaded coming into the job, but ended up not minding as much as I thought I would. PHP, for all of its terrible reputation, functions mostly like how you&#x27;d expect a programming language to function. It does what you ask of it. But there are a lot of dark corners to the language.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;quick-syntax-oddities&quot;&gt;Quick syntax oddities&lt;&#x2F;h2&gt;
&lt;p&gt;But there are some...oddities. I&#x27;ll start with the syntax. As a Rubyist, the opening sigil for declaring or referencing a variable feels &lt;em&gt;super&lt;&#x2F;em&gt; weird:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;php&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$a&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I made this joke to my team: &quot;PHP must be great for startups, because all I see are dollar signs.&quot; Then I proceeded to tell dad jokes for 3 months until management got rid of me. I guess that one was on me.&lt;&#x2F;p&gt;
&lt;p&gt;Then there&#x27;s stabby arrow &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.php.net&#x2F;manual&#x2F;en&#x2F;language.oop5.properties.php&quot;&gt;class property&lt;&#x2F;a&gt; calls, which include functions:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;php&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; Dog&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;    &#x2F;&#x2F; This is a property&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;    public&lt;&#x2F;span&gt;&lt;span&gt; $fur_color&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;brown&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;    function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; woof&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;        echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;woof&lt;&#x2F;span&gt;&lt;span style=&quot;color: #EA76CB;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt; new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; Dog&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;fur_color&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;&#x2F;&#x2F; &amp;quot;brown&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;woof&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;&#x2F;&#x2F; woof&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Another oddity is the array push syntax, which looks like an assignment&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;php&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$a&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; [];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;&#x2F;&#x2F; []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$a&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;[]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;&#x2F;&#x2F; [1]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;But those are just some quirks! They&#x27;re relatively easy to get over. Other issues are not.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;everything-is-a-string&quot;&gt;Everything is a string&lt;&#x2F;h2&gt;
&lt;p&gt;In PHP, if you want to refer to a function, you can just use a string as if it were the function itself:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;php&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; say_hi&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;() {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;hi&lt;&#x2F;span&gt;&lt;span style=&quot;color: #EA76CB;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;#39;say_hi&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;hi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And if you want to reference a class, you can also use a string:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;php&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$klass&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;#39;Dog&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt; new&lt;&#x2F;span&gt;&lt;span&gt; $klass&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;var_dump&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;$d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;object&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;Dog&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;#2 (0) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Oddly enough, using a raw string to reference a class doesn&#x27;t work:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;php&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;#39;Dog&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PHP Parse error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt;  syntax error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; unexpected&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;Dog&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;T_CONSTANT_ENCAPSED_STRING&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt; in php shell code&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt; on&lt;&#x2F;span&gt;&lt;span&gt; line&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Why does this matter? Well, PHP also really likes to do metaprogramming with string composition. So I encountered a lot of code like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;php&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$namespaced_klass&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;\Namespace&lt;&#x2F;span&gt;&lt;span style=&quot;color: #EA76CB;&quot;&gt;\\&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; .&lt;&#x2F;span&gt;&lt;span&gt; $klass&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$object&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt; new&lt;&#x2F;span&gt;&lt;span&gt; $namespaced_klass&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;.&lt;&#x2F;code&gt; concatenates the two strings. Let&#x27;s try this in Ruby:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;klass&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;Animal::&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;Dog&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #179299;&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;Animal::Dog&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; klass&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;Traceback&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;most recent call last&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;        4&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;: ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;NoMethodError&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;undefined method &lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;`new&amp;#39; for &amp;quot;Animal::Dog&amp;quot;:String)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Both languages make string manipulation really easy, but in Ruby, it&#x27;s a lot harder to summon a class or a function from a string, which is actually a feature.&lt;&#x2F;p&gt;
&lt;p&gt;I would oftentimes come across a function like this in our PHP code base:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;php&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; setupClass&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;font-style: italic;&quot;&gt;klass&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    $klass&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;\GlobalNamespace&lt;&#x2F;span&gt;&lt;span style=&quot;color: #EA76CB;&quot;&gt;\\&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; .&lt;&#x2F;span&gt;&lt;span&gt; $klass&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    $thing&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt; new&lt;&#x2F;span&gt;&lt;span&gt; $klass&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    $thing&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;doSomethingIncomprehensible&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;...and I would have no idea where the function &lt;code&gt;doSomethingIncomprehensible&lt;&#x2F;code&gt; would come from, which would add layers of indirection. When you follow the references of &lt;code&gt;setupClass&lt;&#x2F;code&gt;, it was possible to find even more indirection:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;php&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;$some_condition&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    $klass&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; $a&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; .&lt;&#x2F;span&gt;&lt;span&gt; $b&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt; else&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    $klass&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; $a&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; .&lt;&#x2F;span&gt;&lt;span&gt; $c&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;setupClass&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;$klass&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It&#x27;s very &lt;em&gt;convenient&lt;&#x2F;em&gt; for metaprogramming, but it encourages some truly convoluted code.&lt;&#x2F;p&gt;
&lt;p&gt;Also as we can see with trying to instantiate raw string &lt;code&gt;&#x27;Dog&#x27;&lt;&#x2F;code&gt; that it&#x27;s inconsistent.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;error-messages-are-not-helpful&quot;&gt;Error messages are not helpful&lt;&#x2F;h2&gt;
&lt;p&gt;I am very much cheating here comparing PHP to Rust, but let&#x27;s compare what happens when you call a slightly incorrect function name in various languages. Assuming we have a &lt;code&gt;woof&lt;&#x2F;code&gt; method defined on a struct &#x2F; class and we call &lt;code&gt;woog()&lt;&#x2F;code&gt; instead of &lt;code&gt;woof()&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;PHP:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PHP Warning:  Uncaught Error: Call to undefined method Dog::woog() in php shell code:1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Stack trace:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#0 {main}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  thrown in php shell code on line 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Ruby:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Traceback (most recent call last):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        4: from &#x2F;Users&#x2F;brian&#x2F;.rbenv&#x2F;versions&#x2F;3.0.0&#x2F;bin&#x2F;irb:23:in `&amp;lt;main&amp;gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        3: from &#x2F;Users&#x2F;brian&#x2F;.rbenv&#x2F;versions&#x2F;3.0.0&#x2F;bin&#x2F;irb:23:in `load&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        2: from &#x2F;Users&#x2F;brian&#x2F;.rbenv&#x2F;versions&#x2F;3.0.0&#x2F;lib&#x2F;ruby&#x2F;gems&#x2F;3.0.0&#x2F;gems&#x2F;irb-1.3.0&#x2F;exe&#x2F;irb:11:in `&amp;lt;top (required)&amp;gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        1: from (irb):37:in `&amp;lt;main&amp;gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NoMethodError (undefined method `woog&amp;#39; for #&amp;lt;Dog:0x00007f8ec213e450&amp;gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Did you mean?  woof&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Rust:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;error[E0599]: no method named `woog` found for struct `Dog` in the current scope&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --&amp;gt; src&#x2F;main.rs:12:7&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2  | struct Dog;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   | ----------- method `woog` not found for this&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;12 |     d.woog();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   |       ^^^^ help: there is an associated function with a similar name: `woof`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;For more information about this error, try `rustc --explain E0599`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Both Ruby and Rust offer helpful suggestions. PHP does not.&lt;&#x2F;p&gt;
&lt;p&gt;And this is a fairly bog standard error message. PHP error messages get pretty cryptic. The one that stumped me the most was this one:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mockery&#x2F;mockery&#x2F;issues&#x2F;1038&quot;&gt;Serialization of mocked objects in PHP 7.4 · Issue #1038 · mockery&#x2F;mockery&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Exception : Serialization of &#x27;ReflectionClass&#x27; is not allowed&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Which basically boiled down to somewhere, someone used a class that cannot be serialized by mockery, the unit test framework, and PHP absolutely could not tell me which class it was or give me a stack trace.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;global-functions-many-deprecated&quot;&gt;Global functions, many deprecated&lt;&#x2F;h2&gt;
&lt;p&gt;At some point, I wanted to write a function that checks whether a string starts with another string, so I used &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.php.net&#x2F;manual&#x2F;en&#x2F;function.strpos.php&quot;&gt;&lt;code&gt;strpos&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, which purports to &quot;Find the position of the first occurrence of a substring in a string.&quot; Which it does, but PHP&#x27;s type system allows &lt;code&gt;strpos&lt;&#x2F;code&gt; to return either a numeric index or a boolean &lt;code&gt;false&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I assumed &lt;code&gt;strpos&lt;&#x2F;code&gt; returned a numeric value for the index, i.e. a string could safely be assumed to start with another string if &lt;code&gt;index == 0&lt;&#x2F;code&gt;. Sadly, PHP casts &lt;code&gt;false&lt;&#x2F;code&gt; to &lt;code&gt;0&lt;&#x2F;code&gt;, a common aspect of a lot of languages, actually, but one that stumped me for a few days as every string seemed to report starting with every other string. No, &lt;code&gt;strpos&lt;&#x2F;code&gt; was just returning &lt;code&gt;false&lt;&#x2F;code&gt;, which was getting cast to &lt;code&gt;0&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;And yes, I could have double checked with &lt;code&gt;strpos($haystack, $needle) === 0&lt;&#x2F;code&gt; instead of &lt;code&gt;strpos($haystack, $needle) == 0&lt;&#x2F;code&gt;, but I had no idea that &lt;code&gt;strpos&lt;&#x2F;code&gt; could return a boolean.&lt;&#x2F;p&gt;
&lt;p&gt;PHP 8, thankfully, has &lt;code&gt;[str_starts_with](https:&#x2F;&#x2F;www.php.net&#x2F;manual&#x2F;en&#x2F;function.str-starts-with.php)&lt;&#x2F;code&gt; and &lt;code&gt;[str_ends_with](https:&#x2F;&#x2F;www.php.net&#x2F;manual&#x2F;en&#x2F;function.str-ends-with.php)&lt;&#x2F;code&gt;, but we were stuck on an earlier version of PHP.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;few-functional-affordances-cry&quot;&gt;Few functional affordances 😢&lt;&#x2F;h2&gt;
&lt;p&gt;Ruby has postfix functional methods:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;].&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;map&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {|&lt;&#x2F;span&gt;&lt;span&gt;num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt; num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;pow&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #179299;&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 16&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 25&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Which means that you can chain functions that return Enumerables together to stack different effects onto the original array &#x2F; Enumerable:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;].&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;map&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {|&lt;&#x2F;span&gt;&lt;span&gt;num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt; num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;pow&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)}.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;map&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {|&lt;&#x2F;span&gt;&lt;span&gt;num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt; num &lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 2.0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #179299;&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;0.5&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 2.0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 4.5&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 8.0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 12.5&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;PHP does have a map function, but it&#x27;s actually a global function:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;php&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;array_map&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;font-style: italic;&quot;&gt;num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;) {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; $num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span&gt; $num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;}, [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;array&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;  [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;  int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;  [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;  int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;  [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;  int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;9&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;  [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;  int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;  [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;  int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;25&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now suddenly when you want to combine functions it gets very messy, and the order of execution is the opposite of the order you read it in:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;php&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;array_map&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;font-style: italic;&quot;&gt;num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;) {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; $num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; &#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;},&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; array_map&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;font-style: italic;&quot;&gt;num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;) {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; $num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span&gt; $num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;}, [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;]));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;array&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;  [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;  float&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;  [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;  float&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;  [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;  float&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;  [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;  float&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;  [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;  float&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;12&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;a-final-petty-complaint&quot;&gt;A final petty complaint&lt;&#x2F;h2&gt;
&lt;p&gt;All of the above examples were generated in the PHP REPL (&lt;code&gt;php -a&lt;&#x2F;code&gt;) using the &lt;code&gt;[var_dump](https:&#x2F;&#x2F;www.php.net&#x2F;manual&#x2F;en&#x2F;function.var-dump.php)&lt;&#x2F;code&gt; method. Basically, where Ruby&#x27;s REPL (&lt;code&gt;irb&lt;&#x2F;code&gt;) would immediately print a string representation of the result of the expression, PHP would silently perform (or not perform) the expected operation.&lt;&#x2F;p&gt;
&lt;p&gt;Ruby:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;irb&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;main&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;):&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;044&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #179299;&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;irb&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;main&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;):&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;045&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;PHP:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;php &amp;gt; 1 + 1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;php &amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Unless you &lt;code&gt;var_dump&lt;&#x2F;code&gt; it:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;php &amp;gt; var_dump(1 + 1);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;int(2)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;php &amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And if you don&#x27;t, the REPL remains unchanged, which looks frustratingly similar to if you forget to add a semicolon to the end of an expression:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;php &amp;gt; 1 + 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;php &amp;gt; echo &amp;quot;hi&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PHP Parse error:  syntax error, unexpected &amp;#39;echo&amp;#39; (T_ECHO) in php shell code on line 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Parse error: syntax error, unexpected &amp;#39;echo&amp;#39; (T_ECHO) in php shell code on line 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;php &amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note: this error actually means &quot;you forgot a semicolon.&quot; See what I mean about the error messages?&lt;&#x2F;p&gt;
&lt;p&gt;Now that I think of it, there&#x27;s probably a command line flag you can pass to &lt;code&gt;php&lt;&#x2F;code&gt; to get it to behave the way I want, but it should be the default.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Despite all the quirks, it wasn&#x27;t much harder to become productive in PHP than in other dynamic languages. It just happens to be full of papercuts. And, that said, the language itself is still changing and improving - PHP 8 added enums and pattern matching, for example! I was eager to get my grubby little hands on those, but it didn&#x27;t happen before my tenure at the company ended.&lt;&#x2F;p&gt;
&lt;p&gt;Overall, PHP doesn&#x27;t &lt;em&gt;spark joy&lt;&#x2F;em&gt; in me, but I respect that it&#x27;s a beloved tool for many around the world and a workhorse of a language.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>How and why our kids are learning Chinese</title>
        <published>2022-04-13T00:15:28+00:00</published>
        <updated>2022-04-13T00:15:28+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2022/04/13/how-and-why-our-kids-are-learning-chinese/"/>
        <id>https://briankung.dev/2022/04/13/how-and-why-our-kids-are-learning-chinese/</id>
        
        <content type="html" xml:base="https://briankung.dev/2022/04/13/how-and-why-our-kids-are-learning-chinese/">&lt;p&gt;&quot;Are you teaching your kids Chinese?&quot; and &quot;how are you teaching your kids Chinese?&quot; are two questions we get a lot from Chinese American parents. One question I wish more parents asked us is &quot;why?&quot;&lt;&#x2F;p&gt;
&lt;p&gt;When I was picking a major course of study in college, I consistently gravitated towards East Asian Languages and Culture (EALC) with a focus on Chinese for two reasons that I suspect are similar for our friends with a similar background. Those reasons were:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Cultural proximity&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Economic anxiety&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;cultural-proximity&quot;&gt;Cultural proximity&lt;&#x2F;h2&gt;
&lt;p&gt;China is not a monolithic culture. There are 54-odd minorities recognized by the Chinese government and no doubt there are countless more regional dialects.&lt;&#x2F;p&gt;
&lt;p&gt;The variations between dialects of Chinese can be greater than the variation between European languages. For instance, the lexical similarity of Italian and French is 0.89 (out of 1.00 being the same language). Technically, that makes them dialects of each other since the lexical similarity is greater than 0.85 [&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Lexical_similarity#Indo-European_languages&quot;&gt;Wikipedia&lt;&#x2F;a&gt;]. The lexical similarity between Mandarin and Cantonese Chinese is less well-studied, however some claim it to be less than 0.5 [&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;improvemandarin.com&#x2F;mandarin-vs-cantonese&#x2F;&quot;&gt;source&lt;&#x2F;a&gt;]. Informally, it seems to be true - discounting written language, they&#x27;re largely mutually unintelligible.&lt;&#x2F;p&gt;
&lt;p&gt;All this to say, when I went to college, I didn&#x27;t have the opportunity to learn either of my heritage languages - Cantonese or Taishanese (Toisan). I got to pick Mandarin Chinese, Japanese, or Korean. So I tried to pick all of them.&lt;&#x2F;p&gt;
&lt;p&gt;(I did, but I ended up sticking mostly to Chinese.)&lt;&#x2F;p&gt;
&lt;p&gt;Mandarin Chinese was the closest in lexical and cultural similarity, and little did I know that both of my grandmothers spoke it (albeit with colloquial accents).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;economic-anxiety&quot;&gt;Economic anxiety&lt;&#x2F;h2&gt;
&lt;p&gt;This one was much more vague, though I suspect it&#x27;s a much more widely shared reason for learning Chinese than cultural proximity.&lt;&#x2F;p&gt;
&lt;p&gt;In the USA, we hear about China as a vague, foreboding kingdom where freedom-hating serfs bitterly manufacture our mass-market goods while plotting to overthrow our global peacekeeping efforts and supplant themselves as the number one world superpower. So the only way to defeat China is to...make a lot of money off of China?&lt;&#x2F;p&gt;
&lt;p&gt;The kind of discourse one hears about China in America is unhinged, frankly speaking, but it pervades almost every American&#x27;s perspective of Chinese language and culture, including Asian and Chinese Americans.&lt;&#x2F;p&gt;
&lt;p&gt;So when I was in college, my naive assumption was that learning Chinese would help alleviate economic anxiety. It&#x27;s hard to write about this because I didn&#x27;t have a clear idea of what that meant. Similar to how we were told in middle school to learn Spanish to be able to keep up with the business world, I didn&#x27;t know what it meant for my career to learn Chinese.&lt;&#x2F;p&gt;
&lt;p&gt;I &lt;em&gt;hoped&lt;&#x2F;em&gt; that it would mean that either I would have different job opportunities or higher paid job opportunities.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;different-job-opportunities&quot;&gt;Different job opportunities&lt;&#x2F;h3&gt;
&lt;p&gt;As I neared graduation, I started to think about what I could do with my degree in EALC. Taking cues from my seniors, they got into:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Horseback riding&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Pharmaceutical liaison&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Restaurateur&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Grad school&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;...so in short, I learned absolutely nothing. I suspected that the ideal job for an EALC major was to become a translator, ideally for something like the United Nations.&lt;&#x2F;p&gt;
&lt;p&gt;Little did I know:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;filmwonk&#x2F;status&#x2F;1458239012984868867&quot;&gt;https:&#x2F;&#x2F;twitter.com&#x2F;filmwonk&#x2F;status&#x2F;1458239012984868867&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This is backed up by my wife&#x27;s experiences as a medical translator. Cici had a very specialized part time job that required both a doctorate level education in a medical field and high-level understanding of Chinese. There was still no way to make a living doing it.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;📝 Cici&amp;#39;s note: Medical translation was paid per word, and the more you translated or reviewed per unit time, the more money you made. The rate for this job was $50 USD per 1,000 source characters (when translating Chinese to English). I had to negotiate to get that rate. It took roughly 1 hour per 1000 words, and that&amp;#39;s with looking up similar publications to get a feel for phrasing instead of doing word-for-word translations. Note that this is a freelancing job - these numbers are all before taxes and health insurance. The good part is you get to choose your hours.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Theoretically I could find a job &lt;em&gt;in China&lt;&#x2F;em&gt;, but I would have a significant language disadvantage compared to other job seekers. Furthermore, the kinds of jobs you can find in China aren&#x27;t necessarily more economically secure than the ones a college graduate could find in America.&lt;&#x2F;p&gt;
&lt;p&gt;The competitive landscape is also very different for English speakers now than it was 20 years ago. Many more people around the globe are now fluent in English. More people are learning Chinese in countries with closer cultural proximity, as well.&lt;&#x2F;p&gt;
&lt;p&gt;Speaking of which, it&#x27;s not just linguistic competency, but cultural competency that leads to success. Being able to hold a conversation, being able to adapt to the work style - which is generally more top-down, directive based than American work culture. These are easier when your at-home culture is closer to the target culture in question. Needless to say, teaching your child a culture that&#x27;s foreign to you is &lt;em&gt;hard.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;higher-paid-opportunities&quot;&gt;Higher paid opportunities&lt;&#x2F;h3&gt;
&lt;p&gt;So that leads to an even more vague value proposition, which is the possibility that your maximum earning potential goes up when you learn Chinese. It may be true under very specific circumstances, but I would argue that it&#x27;s unlikely to affect your wage ceiling. Let&#x27;s talk about the exceptional cases I can see where this might be true:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Entrepreneurship&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Being able to communicate in Chinese opens up a large potential market for any products or services that you can offer. It also allows you to theoretically tap the Chinese manufacturing and supply chain. So theoretically if you target the Chinese market or if you learn how to manufacture, it would help you a lot.&lt;&#x2F;p&gt;
&lt;p&gt;The downside is that it&#x27;s not necessary. If you&#x27;re running a business, you have more important problems to deal than learning Chinese. If you already know supply chain management and manufacturing, learning Chinese could be a helpful skill if you achieve a high enough level of fluency, which, frankly, is unlikely given the amount of time you&#x27;d have to invest versus the reward.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Media&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;You can make it big in the Chinese entertainment business if you know Chinese very well - and you happen to be non-Asian. Non-Asians and mixed Asians are very disproportionately represented in Chinese media as show hosts or guests. The famous comedian 大山 is representative of this kind of trend. Even our random white friends living in China have gotten calls to be on news stations for no discernible reason.&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately, this is largely inaccessible to the majority of my friends, who are Asian. As Asian Americans, we are largely invisible (or &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;MarvelStudiosSpoilers&#x2F;comments&#x2F;ngeyts&#x2F;simu_liu_responds_to_the_chinese_criticism_he_was&#x2F;&quot;&gt;ugly&lt;&#x2F;a&gt; 🤣) to mainland Chinese people. When we are visible, we are seen as defective if we &lt;em&gt;don&#x27;t&lt;&#x2F;em&gt; speak Chinese. Non-Asians, however, are regularly applauded for speaking even basic Chinese, which creates a positive feedback loop for continuing to learn.&lt;&#x2F;p&gt;
&lt;p&gt;In China, non-Asians are exotic and interesting and they represent The West, which China has a complicated relationship with as an ascending super power. Asians are just meh.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-learn-chinese&quot;&gt;Why learn Chinese?&lt;&#x2F;h2&gt;
&lt;p&gt;Learning Chinese is hard and not necessarily financially rewarding. As parents, we have to question whether the time investment is worth it when the kids are so young, especially with the amount of money that can be poured into it with learning materials, tutors, and immersion schools. And we&#x27;ve seen friends do well learning Chinese starting in high school. So why teach kids, especially young kids, Chinese?&lt;&#x2F;p&gt;
&lt;p&gt;Our kids are learning Chinese anyway. Ultimately, it&#x27;s because the reasons are not financial. And, as you&#x27;ll see, we think those are the best motivators for the kids, anyway.&lt;&#x2F;p&gt;
&lt;p&gt;We struggle with how to teach our kids Chinese because I grew up without a good understanding of my grandparents, and because my wife&#x27;s parents have a tenuous grasp of English themselves. And Cici&#x27;s childhood in China gave her an appreciation of the culture that she wants to share with us. It comes down to our cultural connections.&lt;&#x2F;p&gt;
&lt;p&gt;Our kids watch a lot of Chinese shows, a few of them being shows that Cici watched as a kid, but also a few new ones. Ironically, cultural connection to China means quite the opposite of being productive in a capitalist culture. The fact that our kids can appreciate Chinese shows means that they can appreciate shows, media, and the arts from an entirely different country. During the pandemic, we have all discovered the importance of turning to the arts to keep our spirits up. They have a lot more opportunities to do so, being able to watch Chinese or English shows.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s just, like, &lt;em&gt;fun&lt;&#x2F;em&gt;, man.&lt;&#x2F;p&gt;
&lt;p&gt;Secondly, when I went to college, my aim with learning Chinese was to be able to communicate with my grandparents better. Sadly, Cantonese isn&#x27;t offered at very many colleges (I think it&#x27;s just Yale), and my grandparents spoke an even more obscure dialect of Chinese called Toisan (台山话 &#x2F; Taishan). So due to cultural proximity, Mandarin Chinese was the closest I could get to studying my family&#x27;s language in college. I took it and thankfully my grandmothers both speak Mandarin to some degree, so it has helped.&lt;&#x2F;p&gt;
&lt;p&gt;But it was still over twenty years before I could make myself understood to them using sentences more complex than &quot;I like &lt;noun&gt;.&quot; Those twenty years weigh on me. My 奶奶 (paternal grandmother) has passed away, and I&#x27;m glad we were able to visit her consistently after the birth of our son, but I want - and cannot have - more time.&lt;&#x2F;p&gt;
&lt;p&gt;I don&#x27;t want that for my kids.&lt;&#x2F;p&gt;
&lt;p&gt;While my parents speak Cantonese and Toisan, they speak English by preference now. But Cici&#x27;s parents are still much more comfortable in Mandarin Chinese. I&#x27;m not worried about our kids learning English - they will pick it up. But we are worried that they won&#x27;t be able to connect with their maternal grandparents linguistically or culturally.&lt;&#x2F;p&gt;
&lt;p&gt;And so we make sure to expose them to a good deal of Chinese when we can, even though we speak to each other in English. We put in a consistent amount of moderate effort to do these things.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-we-re-teaching-the-kids-chinese&quot;&gt;How we&#x27;re teaching the kids Chinese&lt;&#x2F;h2&gt;
&lt;p&gt;Cici has seen it from the lens of learning English as a foreign language as a child, and I&#x27;ve come at it from the other end, learning Chinese as a foreign language as an adult, and we&#x27;ve converged on the same set of principles. We feel that the key to success is to cultivate the kids&#x27; personal reasons for learning Chinese.&lt;&#x2F;p&gt;
&lt;p&gt;We both agree that workbooks, passive learning, and other explicit &lt;em&gt;language learning&lt;&#x2F;em&gt; activities are very poor motivators, poor motivation leads to poor engagement, and poor engagement leads to poor retention.&lt;&#x2F;p&gt;
&lt;p&gt;Cici remembers her mom turning on the AM radio on long trips in the USA for &quot;passive learning&quot; and my wife would just zone out. When she was bored enough, she would tune in, but wouldn&#x27;t really catch anything. She has done the workbooks and the exercises and the memorization, but nothing of consequence stuck before moving to the US.&lt;&#x2F;p&gt;
&lt;p&gt;Even as recently as just a few years ago, I was writing and rewriting characters to memorize them and I can confidently say I recall almost none of the pages of characters I wrote. In college, I learned thrilling words like &quot;bill of lading&quot; in Chinese, which I would say I forgot but in truth never truly managed to learn. And we both have friends who recounted ruefully that they spent plenty of weekends in Chinese school only to forget it as soon as they stopped, or worse, grew to hate it.&lt;&#x2F;p&gt;
&lt;p&gt;But what did work for Cici as a tween was learning lyrics of the songs her friends were into. I still remember Chinese lyrics of songs I learned 15 years ago, and learning songs in English or Chinese is something we still connect on today.&lt;&#x2F;p&gt;
&lt;p&gt;The key idea for us was to focus on the content, not the language learning itself. The learning would come if the content was engaging. And so we did our best to craft a miniature digital Chinese immersion environment through media exposure including apps, everyday communication, and a restricted English media diet. Importantly, though their options are limited, they choose what they want to do.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Learn Chinese myself&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;First of all, as the parent least comfortable in Chinese, it&#x27;s my responsibility to try to continue to learn and push myself to learn Chinese. In day to day interactions, I try to use mostly Chinese with our children unless I really just don&#x27;t know how to say something. And if it bothers me enough, it&#x27;s a sign that I need to learn the word for it.&lt;&#x2F;p&gt;
&lt;p&gt;This is hard with a busy schedule. Theoretically I should keep flash cards for words I should or am currently learning, but that&#x27;s a little too much overhead for me right now, so I just try to learn with my kids.&lt;&#x2F;p&gt;
&lt;p&gt;I think if I had married a partner who spoke a different, non-heritage (for me) language, I would likely try to do the same.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Accept that code-switching is a part of life&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Code switching, or switching between languages, is a perfectly natural part of life, even for native Chinese speakers. Accepting that we&#x27;ll be mixing Chinese and English makes it easier to work vocabulary into your current patterns of speech. Accepting that your children will code switch makes it easier to accept that some days they&#x27;ll feel like speaking English, and some days they&#x27;ll feel like speaking Chinese.&lt;&#x2F;p&gt;
&lt;p&gt;Importantly, code switching should not be seen as a deficiency by default. If your kids code switch with each other, they might be reinforcing each others&#x27; vocabulary in a mix of languages. And in countries like Malaysia, code switching is part of living in a multilingual country. Cici&#x27;s Malaysian friend can code switch between Malay, English, and Chinese in the same sentence. It&#x27;s not because she can&#x27;t think of the words in each language, she&#x27;s simply using the words that are the closest proximity to the idea she&#x27;s trying to express.&lt;&#x2F;p&gt;
&lt;p&gt;I will also sometimes code switch on purpose because I know that I can connect the ideas of one language that aren&#x27;t particularly strong in another. As a contrived example, we use the word 洗澡 or bathe&#x2F;shower all the time. So if my son points at a car wash and asks &quot;what is that?&quot; I can say it&#x27;s a 车洗澡的地方 or &quot;a place for cars to bathe.&quot; Or when I can easily explain something in English, I start with an explanation or a word in Chinese to let him struggle with the meaning before explaining it in English.&lt;&#x2F;p&gt;
&lt;p&gt;That said, I do think patterns of code switching and the inability to think of words in a language are actual weaknesses. We also need to encourage them to speak Chinese, ultimately. It&#x27;s the speaking of the language that really cements it for the long run. I know this as a child who used to speak Cantonese a lot better than I do now. Once I stopped speaking it, I began to lose the ability to even speak the phonemes correctly, which made me even more self-conscious and less likely to learn.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Restrict English media&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;English media is a pervasive fact of life in America, and we try not to have anything to do with it. They will never lack for English media, and the latest and greatest cartoons and animations will be in English, so we do not allow unfettered access to English media.&lt;&#x2F;p&gt;
&lt;p&gt;That means no YouTube, time limits on English media apps like WTTW, and supervised access for shows on Disney+, which we watch in the Taiwanese Mandarin localization whenever possible.&lt;&#x2F;p&gt;
&lt;p&gt;In America, access to English media will never be a limitation. It can easily become an addiction, though, and for a kid, the language of entertainment quickly becomes the language of preference.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Encourage Chinese media&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;That said, there are a lot of Chinese shows &lt;em&gt;on&lt;&#x2F;em&gt; YouTube that we would like for the kids to be able to access, and for that, I use &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yt-dlp&#x2F;yt-dlp&quot;&gt;yt-dlp&lt;&#x2F;a&gt; to download entire playlists at a time. Then for access, I run a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;jellyfin.org&#x2F;&quot;&gt;Jellyfin&lt;&#x2F;a&gt; instance on my iMac to serve the videos over our router. Yes, being a programmer helps a lot, especially since setting up Jellyfin to be actually usable took a lot of tweaking.&lt;&#x2F;p&gt;
&lt;p&gt;Here are some shows on YouTube that we self-host:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;宝宝巴士 - Baby Bus: shows, lullabies, and nursery rhymes good for babies and up&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;巧虎 - Qiaohu: lots of Asian-style life lessons. Qiaohu was teaching kids to wear masks 3 years before the Covid-19 pandemic&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;海底小纵队 - Octonauts: a show about saving animals in the ocean that our kids loved&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;小猪佩奇 - Peppa Pig: not the parents&#x27; favorite show because the characters can be kind of obnoxious, but the kids like it&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Additionally for older kids, our 8yo has enjoyed:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;叶罗丽 - Yeluoli, a show about magical dolls and fighting evil&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;小花仙 - Xiaohuaxian, a story about a girl with a magic bracelet&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;绿野仙踪 - The Wizard of Oz: a favorite of Cici&#x27;s from her childhood. It&#x27;s an anime remix of the Wizard of Oz that was originally in Japanese, but she watched it as a kid in China&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;还珠格格 - A period drama about a fake princess&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;白蛇 - An animated movie about a demon snake and the snake catcher who finds her - EDIT - I forgot this one’s not a kids’ show. There is definitely a sex scene. That said, it’s pretty subtle and it went over our kids’ heads.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;You can filter your YouTube search results for playlists. When you give &lt;code&gt;yt-dlp&lt;&#x2F;code&gt; the URL of a playlist, it will download the entire thing.&lt;&#x2F;p&gt;
&lt;p&gt;There are also a few shows &#x2F; movies that the kids enjoy on Disney+ in the Taiwanese Mandarin localization:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The Lion Guard - a show about one of Simba&#x27;s sons. Almost the entire show has been localized in Taiwanese Mandarin.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Bluey - a show about an Australian dog family. About a third or a fourth of this show has been localized. Update - the entirety of this show, as far as I can tell, has been translated! 🎉&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Finally, we used to let the kids watch YouKu as much as they want, but unfortunately there are stupid slapstick humor shows on that as well that our son loves and learns bad habits from. It&#x27;s still more regulated than YouTube though, so we feel safer letting them have unsupervised access than we do with YouTube.&lt;&#x2F;p&gt;
&lt;p&gt;📖 Story time: When our eldest was maybe 3 or 4, we would tell Cici&#x27;s parents not to let her watch YouTube without them. Time and time again, we would come back to find her watching YouTube on her own. One time - one of the last times - I came downstairs to find her watching YouTube on the television. The video in question involved a giant cartoon baby face that stretched across the length of the TV. The corners of its mouth were held open by raven claws reaching in from the corners of the screen. The baby looked like it was in pain and occasionally shed a tear. At the bottom of the screen, a conveyor belt brought random objects to the baby&#x27;s mouth which were force-fed to the baby. It was like something out of a feverish nightmare. So, and pardon my French, &lt;em&gt;fuck YouTube&#x27;s algorithm&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Exposure via family&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We have Cici&#x27;s mom stay over roughly 4 days out of the week because it would be impossible for us both to work without a third adult to help keep the kids safe, and it helps us expose the kids to Chinese through relatives. We&#x27;re not always the best at speaking to the kids in Chinese, but Cici&#x27;s mom is significantly more comfortable speaking Chinese than English, so Chinese remains her default mode of communication. It helps a lot, but she doesn&#x27;t consistently push them to use Chinese, which is something we&#x27;re working on. Cici&#x27;s dad is also a comedic figure and likes Chinese word play.&lt;&#x2F;p&gt;
&lt;p&gt;Adorably, when our children see &lt;em&gt;my&lt;&#x2F;em&gt; maternal grandma, they can communicate with her, too. ❤️&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Apps&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We have a few different learning apps installed, and they are some of the few that don&#x27;t have time limits on them, so when they go on long screen time binges, which is unfortunately too often, they end up doing more Chinese apps. One of the most effective is iHuman&#x27;s 洪恩识字 app. Our son also has a favorite that I&#x27;ll update this article with when I can find it.&lt;&#x2F;p&gt;
&lt;p&gt;EDIT - found them:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;iHuman 洪恩识字&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;2Kids 识字&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;2Kids Chinese&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;2Kids 学拼音&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;2Kids 数学天天练&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Ideally, try to let the kids use the app in Chinese mode, not English mode for full immersion. That means for Chinese illiterate parents, the UI will be inscrutable. But breaking the immersion is costly. On a meta level, it&#x27;s not just engagement with the content that&#x27;s important in this case, but engagement with navigating the content, which helps them navigate content anywhere. Avery has mentioned that she knows characters because she knows what buttons labeled with those characters do. Also a lot of Chinese apps ironically emphasize learning English, which is very annoying.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Neglect handwriting&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We have almost no emphasis on having the kids learn handwriting beyond possibly writing their names. When we teach the kids characters, we let them use pinyin keyboards to write in Chinese. Otherwise this would all take much, much more effort for less reward.&lt;&#x2F;p&gt;
&lt;p&gt;That said, the apps they use do have handwriting sections, and if they enjoy it, well, good for them!&lt;&#x2F;p&gt;
&lt;h3 id=&quot;different-strokes&quot;&gt;Different strokes&lt;&#x2F;h3&gt;
&lt;p&gt;When our eldest daughter was around 4 years old, she was going to daycare with English-speaking caretakers and gushing over PJ Mask with her friends. I became alarmed when she started responding to her grandparents&#x27; Chinese inquiries in English. Part of it no doubt was her interest in hearing their accents in English, but a large part was that she was just becoming more comfortable speaking English than Chinese, &lt;em&gt;even in Chinese language contexts.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I had lived thirty-plus years of that, and I found the possibility of that outcome intolerable.&lt;&#x2F;p&gt;
&lt;p&gt;Now, our oldest daughter&#x27;s Chinese is &lt;em&gt;decidedly&lt;&#x2F;em&gt; better than mine in every dimension. She&#x27;s basically literate and able to pick up new characters much more quickly due to her verbal fluency and familiarity with ~1.5k characters.&lt;&#x2F;p&gt;
&lt;p&gt;We have been homeschooling our children since the start of the pandemic and are planning on continuing to do so until all of our children can get the Covid-19 vaccine. That means we set the school curriculum, which includes an hour of Chinese using 洪恩识字 each school day, in which Cici emphasizes sentence composition. We incentivize by letting her watch YouKu or Jellyfin afterwards.&lt;&#x2F;p&gt;
&lt;p&gt;Her Chinese has really blossomed under these circumstances, and she&#x27;s eager to read every Chinese character she can find, and she enjoys messaging her 阿婆 (maternal grandma) in Chinese.&lt;&#x2F;p&gt;
&lt;p&gt;But I don&#x27;t think the method of instruction would work with every kid. Our 3 year old son, for instance, would probably hate sitting down to study at any age and I doubt there will ever be an cajoling, incentivizing, or punishment that would get him to do it.&lt;&#x2F;p&gt;
&lt;p&gt;Right now, our son is exploring Chinese through the apps that we have and we appreciate that he likes to play on the Chinese learning apps about as much as the English ones.&lt;&#x2F;p&gt;
&lt;p&gt;Ultimately, language learning for the kids has to be something that they enjoy.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Ruby has economy-class functions</title>
        <published>2022-03-27T12:26:38+00:00</published>
        <updated>2022-03-27T12:26:38+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2022/03/27/ruby-has-economy-class-functions/"/>
        <id>https://briankung.dev/2022/03/27/ruby-has-economy-class-functions/</id>
        
        <content type="html" xml:base="https://briankung.dev/2022/03/27/ruby-has-economy-class-functions/">&lt;p&gt;🇺🇦 &lt;em&gt;I&#x27;m joining the Ruby community in calling for an end to Russia&#x27;s unjust and illegal war in Ukraine! Please donate to Ukrainian efforts &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ua-aid-centers.com&#x2F;funds-and-foundations&quot;&gt;here&lt;&#x2F;a&gt; and learn more &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;war.ukraine.ua&#x2F;&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;em&gt; 🇺🇦&lt;&#x2F;p&gt;
&lt;p&gt;Ruby has economy-class functions, not first-class functions. And that&#x27;s okay! It&#x27;s a great language anyway.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s talk about what first-class functions look like. Per the Wikipedia entry, a programming language is considered to support first-class functions if it:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Non-local variables and closures&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Functions that maintains the environment (and therefore the variables) that was in-scope when the function was created.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Anonymous and nested functions&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Functions that aren&#x27;t bound to a variable. Why? So we can pass them into other functions without first needing to assign them to a variable. And &quot;nested function&quot; just means a function that is defined while calling another function.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Higher order functions&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Functions that can take other functions as arguments and return them as well.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The good news is that Ruby supports most of these use cases! But not in a way that I&#x27;d consider first-class. Economy, perhaps, but not first-class. Let&#x27;s talk about each one in turn&lt;&#x2F;p&gt;
&lt;h3 id=&quot;non-local-variables-and-closures&quot;&gt;Non-local variables and closures&lt;&#x2F;h3&gt;
&lt;p&gt;Ruby supports this aspect of first-class functions!&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;a&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;#=&amp;gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;b&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;#=&amp;gt; 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; lambda&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {|&lt;&#x2F;span&gt;&lt;span&gt;c&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt; a &lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt; b &lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt; c&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;#=&amp;gt; #&amp;lt;Proc:0x0000000108d29d90 (irb):3 (lambda)&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;#=&amp;gt; 6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Verdict: ✅ Arguably Ruby popularized the use of anonymous functions in other languages, even to the extent of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;book&#x2F;ch13-01-closures.html#refactoring-with-closures-to-store-code&quot;&gt;inspiring Rust&#x27;s syntax for anonymous functions.&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;anonymous-and-nested-functions&quot;&gt;Anonymous and nested functions&lt;&#x2F;h3&gt;
&lt;p&gt;Again, another case where Ruby shines. If you&#x27;ve provided a block to an argument, you&#x27;ve used Ruby&#x27;s fantastic language-level support for anonymous functions:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;array&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;..&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;15&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;to_a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;#=&amp;gt; [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             👇 anonymous function!&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;array&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;select&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {|&lt;&#x2F;span&gt;&lt;span&gt;number&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt; number&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;even?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;#=&amp;gt; [2, 4, 6, 8, 10, 12, 14]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Nesting functions is a less common pattern, but it &lt;em&gt;is&lt;&#x2F;em&gt; slightly more awkward, and you have to &lt;em&gt;know things&lt;&#x2F;em&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;def&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; uses_a_function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;font-style: italic;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      👇 but why?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;call&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                👇 🤔&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;uses_a_function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;font-style: italic;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;font-style: italic;&quot;&gt; b&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;span&gt;a &lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt; b&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;#=&amp;gt; 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If this particular &lt;em&gt;knowing of things&lt;&#x2F;em&gt; is troubling to you, it should give you a sense of deep foreboding for the next section.&lt;&#x2F;p&gt;
&lt;p&gt;Verdict: ✅ who needs nested functions, anyway?&lt;&#x2F;p&gt;
&lt;h3 id=&quot;higher-order-functions&quot;&gt;Higher order functions&lt;&#x2F;h3&gt;
&lt;p&gt;Next, let&#x27;s try to return functions from functions in Ruby:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;def&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; returns_function&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; addition&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;font-style: italic;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;font-style: italic;&quot;&gt; b&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    a &lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt; b&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Easy! Well, not really:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;add&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; returns_function&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;#=&amp;gt; :addition&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;add&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;irb&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;):&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D20F39;&quot;&gt;in&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; `&amp;lt;main&amp;gt;&amp;#39;: undefined method `&lt;&#x2F;span&gt;&lt;span&gt;add&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;#39; for main:Object (NoMethodError)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can do this pretty handily in Javascript:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; returnsFunction&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt; function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;  return function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;font-style: italic;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;font-style: italic;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;) {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; a&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span&gt; b&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; addition&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; returnsFunction&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;addition&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;&#x2F;&#x2F; 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You &lt;em&gt;can&lt;&#x2F;em&gt; do this in Ruby, it&#x27;s just more...&lt;em&gt;economy&lt;&#x2F;em&gt; class. The aisles are tighter and you have a longer line to board:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;def&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; returns_function&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;  Proc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;new do&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span&gt;a&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt;b&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    a &lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt; b&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;  # or you could use a lambda:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;  -&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;font-style: italic;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;font-style: italic;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;span&gt;a &lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt; b&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;  # ...which is shorthand for:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;  lambda&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {|&lt;&#x2F;span&gt;&lt;span&gt;a&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt;b&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt; a &lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt; b&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;addition&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; returns_function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And then you can use it like a normal function...except that you can&#x27;t because it&#x27;s a &lt;code&gt;Proc&lt;&#x2F;code&gt; (or a &lt;code&gt;Lambda&lt;&#x2F;code&gt;) and not a method as supported by the language:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;irb&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;main&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;):&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;008&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; addition&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;irb&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;):&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D20F39;&quot;&gt;in&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; `&amp;lt;main&amp;gt;&amp;#39;: undefined method `&lt;&#x2F;span&gt;&lt;span&gt;addition&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;#39; for main:Object (NoMethodError)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So you have to get back in the economy class line:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;addition&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;call&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;#=&amp;gt; 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;# or the shorthand version:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;addition&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;#=&amp;gt; 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Alternately, you can use the &lt;code&gt;def...end&lt;&#x2F;code&gt; syntax in Ruby, as long as you know that a method definition returns the method&#x27;s &lt;code&gt;Symbol&lt;&#x2F;code&gt; instead of the actual &lt;code&gt;Method&lt;&#x2F;code&gt; object:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;def&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; returns_function&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;  def&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; addition&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;font-style: italic;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;font-style: italic;&quot;&gt; b&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    a &lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt; b&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;add&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; returns_function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;#=&amp;gt; :addition&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;# Note that calling returns_function has actually defined the addition method in the caller&amp;#39;s scope, but let&amp;#39;s pretend we didn&amp;#39;t know that&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;add&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;class&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;#=&amp;gt; Symbol&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;# Now we go from a Symbol to a method with the Object#method class:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;add&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; method&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;add&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #179299;&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt; #&amp;lt;Method: Object#addition(a, b) (irb):2&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;# And now we can finally call it:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;add&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;#=&amp;gt; 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You &lt;em&gt;can&lt;&#x2F;em&gt; do it, but the obstacles with the language dissuade you from currying, passing functions around, and calling them. Furthermore, even if you were to shoehorn Ruby into a first-class function usage patterns, you would have to know the differences between methods, procs, and lambdas, and how to call them. As a result, the large majority of the Ruby ecosystem does not use functions in a first-class manner, which is disappointing because the support for it is &lt;em&gt;so close.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;A large portion of support would be getting &lt;em&gt;method references&lt;&#x2F;em&gt;, i.e. a shorthand for &lt;code&gt;Object#method&lt;&#x2F;code&gt; which would let us refer to methods without the ceremony of calling &lt;code&gt;method(:some_method&#x27;s_symbol)&lt;&#x2F;code&gt;. In fact, support for method references was added at some point, but then removed. So instead of calling &lt;code&gt;method(:some_method&#x27;s_symbol)&lt;&#x2F;code&gt;, the proposal was to create a language level syntactical sugar for it using &lt;code&gt;.:some_method&#x27;s_symbol&lt;&#x2F;code&gt;. And here is the feature request in Ruby&#x27;s bug tracker: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;bugs.ruby-lang.org&#x2F;issues&#x2F;13581#note-45&quot;&gt;https:&#x2F;&#x2F;bugs.ruby-lang.org&#x2F;issues&#x2F;13581#note-45&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The other part would be the awkwardness around calling the returned method, but that seems unavoidable at this point due to the ambiguity caused by Ruby not requiring parentheses in order to call a method.&lt;&#x2F;p&gt;
&lt;p&gt;Verdict: ⚠️ technically yes, but realistically no. It&#x27;s not great and it doesn&#x27;t lead to the sorts of usage patterns that you see in other languages with first-class functions.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Note: I have to point out that the &lt;code&gt;.:&lt;&#x2F;code&gt; syntax was proposed by &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;zverok&quot;&gt;Victor Shepelev aka zverok&lt;&#x2F;a&gt;, who is a Ukrainian Ruby core member who is currently sheltering in Kharkiv, one of the many cities under attack by Russian forces. Read recent developments &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;zverok.space&#x2F;blog&#x2F;2022-03-15-STILL-WAR.html&quot;&gt;here&lt;&#x2F;a&gt;, and zverok&#x27;s blog &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;zverok.space&#x2F;writing&#x2F;#blog&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Writing a Rust gem from scratch</title>
        <published>2022-02-02T18:02:14+00:00</published>
        <updated>2022-02-02T18:02:14+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2022/02/02/writing-a-rust-gem-from-scratch/"/>
        <id>https://briankung.dev/2022/02/02/writing-a-rust-gem-from-scratch/</id>
        
        <content type="html" xml:base="https://briankung.dev/2022/02/02/writing-a-rust-gem-from-scratch/">&lt;p&gt;&lt;em&gt;Note: anytime you see&lt;&#x2F;em&gt; 🙋‍♂️ RFC_, that&#x27;s a &quot;Request For Comments&quot; about a topic I didn&#x27;t understand or take the time to look into. Please feel free to add what you know!_&lt;&#x2F;p&gt;
&lt;p&gt;This is a followup to the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;briankung.dev&#x2F;2022&#x2F;01&#x2F;31&#x2F;sneak-preview-writing-ruby-gem-native-extensions-in-rust&#x2F;&quot;&gt;last post.&lt;&#x2F;a&gt; Instead of using the template &lt;code&gt;rust_ruby_example&lt;&#x2F;code&gt; gem, we&#x27;ll make one from scratch. Make sure to go back over the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;briankung.dev&#x2F;2022&#x2F;01&#x2F;31&#x2F;sneak-preview-writing-ruby-gem-native-extensions-in-rust&#x2F;#using-a-rubygems-fork&quot;&gt;&quot;Using a &lt;code&gt;rubygems&lt;&#x2F;code&gt; fork&quot;&lt;&#x2F;a&gt; section because we&#x27;ll be using it heavily during this post, as well!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;requirements&quot;&gt;Requirements&lt;&#x2F;h2&gt;
&lt;p&gt;Requirements &#x2F; dependencies &#x2F; utilities I used and their versions on macOS Monterey v12.1 (21C52) as of 2022-02-02:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Bundler version 2.4.0.dev&lt;&#x2F;li&gt;
&lt;li&gt;gem version 3.4.0.dev&lt;&#x2F;li&gt;
&lt;li&gt;cargo 1.58.0 (f01b232bc 2022-01-19)&lt;&#x2F;li&gt;
&lt;li&gt;rustc 1.58.1 (db9d1b20b 2022-01-20)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;generating-a-new-gem&quot;&gt;Generating a new gem&lt;&#x2F;h2&gt;
&lt;p&gt;Let&#x27;s see what it takes to write a Rust gem from scratch. Thankfully, Bundler has a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;bundler.io&#x2F;guides&#x2F;creating_gem.html&quot;&gt;generator for making new gems&lt;&#x2F;a&gt;, and we can look at the &lt;code&gt;[rust_ruby_example](https:&#x2F;&#x2F;github.com&#x2F;briankung&#x2F;rust_ruby_example)&lt;&#x2F;code&gt; gem for pointers on how to get the Rust parts working.&lt;&#x2F;p&gt;
&lt;p&gt;We&#x27;re still going to be doing some string manipulation, but this time we&#x27;ll just shuffle the characters. Full disclosure: I also don&#x27;t know enough of Ruby&#x27;s C API to do much more than that. That&#x27;s an adventure for another day!&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s start out by asking &lt;code&gt;bundler&lt;&#x2F;code&gt; to make a new gem. We&#x27;ll call it &lt;strong&gt;r&lt;&#x2F;strong&gt;ust_sh&lt;strong&gt;uffle&lt;&#x2F;strong&gt;, or &lt;strong&gt;&lt;code&gt;ruffle&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; for short.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-000-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-000-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If this is the first time you&#x27;ve created a new gem with &lt;code&gt;bundler&lt;&#x2F;code&gt;, it may ask you a few configuration questions first. These questions are saved to your user&#x27;s profile at &lt;code&gt;~&#x2F;.bundle&#x2F;config&lt;&#x2F;code&gt; and can be changed with the &lt;code&gt;bundle config&lt;&#x2F;code&gt; subcommand. For our purposes, the only one that matters is using &lt;code&gt;rspec&lt;&#x2F;code&gt; as the test framework.&lt;&#x2F;p&gt;
&lt;p&gt;Speaking of &lt;code&gt;rspec&lt;&#x2F;code&gt;, let&#x27;s &lt;code&gt;$ bundle install&lt;&#x2F;code&gt; in our new &lt;code&gt;ruffle&lt;&#x2F;code&gt; directory so we can fetch the &lt;code&gt;rspec&lt;&#x2F;code&gt; gem:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-001-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-001-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Well! Looks like we&#x27;ll be using some good old-fashioned EDD (Error Driven Development) to get this gem ship-shape.&lt;&#x2F;p&gt;
&lt;p&gt;The problem here is that the gemspec, a metadata file, needs to be filled out before the gem is valid. We&#x27;re going to do it the easy way and simply remove all the &lt;code&gt;TODO&lt;&#x2F;code&gt;&#x27;s from the. Bundler also checks that the URLs parse correctly, so we&#x27;ll be replacing all the URLs with &lt;code&gt;&quot;https:&#x2F;&#x2F;example.com&quot;&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-002-rb&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-002-rb&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;And now we can fetch our dependencies:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-003-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-003-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Now, what happens when we run our specs?&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-004-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-004-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The test &quot;Ruffle does something useful&quot; in the file &lt;code&gt;spec&#x2F;ruffle_spec.rb&lt;&#x2F;code&gt; on line 8 fails. Harsh.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;adding-a-shuffle-method-in-rust&quot;&gt;Adding a &lt;code&gt;#shuffle&lt;&#x2F;code&gt; method in Rust&lt;&#x2F;h2&gt;
&lt;p&gt;First, let&#x27;s change the &quot;does something useful&quot; test to &lt;em&gt;test&lt;&#x2F;em&gt; something useful. Replace &lt;code&gt;spec&#x2F;ruffle_spec.rb&lt;&#x2F;code&gt; with the following:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-005-rb&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-005-rb&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Now let&#x27;s run the test, like good EDD practitioners - red, green, deploy. Then right back to EDD, this time in prod (it&#x27;s a virtuous cycle):&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-006-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-006-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;You may see a warning like &lt;code&gt;--pattern spec&#x2F;**{,&#x2F;*&#x2F;**}&#x2F;*_spec.rb failed&lt;&#x2F;code&gt;. This is a result of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;36427818&#x2F;rspec-showing-error-message&quot;&gt;running &lt;code&gt;rspec&lt;&#x2F;code&gt; through &lt;code&gt;rake&lt;&#x2F;code&gt;.&lt;&#x2F;a&gt; While it&#x27;s annoying, it&#x27;s not a showstopper.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;initializing-a-rust-project&quot;&gt;Initializing a Rust project&lt;&#x2F;h3&gt;
&lt;p&gt;Now let&#x27;s add some Rust code! For the purposes of this tutorial, we&#x27;ll add it directly to the root directory of the gem, but there is a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rake-compiler&#x2F;rake-compiler#using-a-standardized-project-structure&quot;&gt;standard project structure&lt;&#x2F;a&gt; for gem native extensions.&lt;&#x2F;p&gt;
&lt;p&gt;(🙋‍♂️ RFC: should a Rust extension follow the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rake-compiler&#x2F;rake-compiler#using-a-standardized-project-structure&quot;&gt;&lt;code&gt;rake-compiler&lt;&#x2F;code&gt; project structure&lt;&#x2F;a&gt;?)&lt;&#x2F;p&gt;
&lt;p&gt;You can initialize a Rust project with:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-007-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-007-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We pass the &lt;code&gt;--lib&lt;&#x2F;code&gt; argument to &lt;code&gt;cargo&lt;&#x2F;code&gt; to tell it that we want our crate to be a library, not a binary. Whereas a binary results in an executable, a library crate&#x27;s output should be something like &lt;code&gt;.so&lt;&#x2F;code&gt; or &lt;code&gt;.dll&lt;&#x2F;code&gt; files, if not compiled directly into another Rust binary.&lt;&#x2F;p&gt;
&lt;p&gt;Now we have two new files: &lt;code&gt;Cargo.toml&lt;&#x2F;code&gt; and &lt;code&gt;src&#x2F;lib.rs&lt;&#x2F;code&gt;. &lt;code&gt;cargo&lt;&#x2F;code&gt; has also modified the &lt;code&gt;.gitignore&lt;&#x2F;code&gt; file to ignore build artifacts and &lt;code&gt;Cargo.lock&lt;&#x2F;code&gt;, a lockfile for Cargo dependencies.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;adding-a-rake-compile-task&quot;&gt;Adding a &lt;code&gt;rake compile&lt;&#x2F;code&gt; task&lt;&#x2F;h3&gt;
&lt;p&gt;Let&#x27;s add a &lt;code&gt;rake&lt;&#x2F;code&gt; task to compile our Rust code. &lt;code&gt;Rakefile&lt;&#x2F;code&gt;s are Ruby files that define the tasks that &lt;code&gt;rake&lt;&#x2F;code&gt; can run. If we inspect ours, it looks fairly barebones:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-008-rb&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-008-rb&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Basically it requires some default tasks. It also defines the &lt;code&gt;:spec&lt;&#x2F;code&gt; task as the default task, or the task that&#x27;s run when you execute &lt;code&gt;rake&lt;&#x2F;code&gt; without any arguments. We&#x27;ve already used it, in fact.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s add a &lt;code&gt;compile&lt;&#x2F;code&gt; task. Make sure the &lt;code&gt;RUBYGEMS_PATH&lt;&#x2F;code&gt; environment variable is set &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;briankung.dev&#x2F;2022&#x2F;01&#x2F;31&#x2F;sneak-preview-writing-ruby-gem-native-extensions-in-rust&#x2F;#aliasing-your-default-rubygems&quot;&gt;from the last post&lt;&#x2F;a&gt;. If you don&#x27;t have it, make sure to export it:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-013-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-013-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Now we can reference that:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-014-3-rb&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-014-3-rb&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;💡 &lt;strong&gt;Click&lt;&#x2F;strong&gt; for additional notes - &lt;code&gt;*cargo_builder_gem&lt;&#x2F;code&gt;?&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;We have to make sure we&#x27;re using the &lt;code&gt;cargo-builder&lt;&#x2F;code&gt; branch of rubygems. If we simply shell out to &lt;code&gt;gem&lt;&#x2F;code&gt;, we&#x27;ll end up using our default system gem.&lt;&#x2F;p&gt;
&lt;p&gt;I was hoping to use the &lt;code&gt;rubygem&lt;&#x2F;code&gt; internals to build the gem instead of relying on shelling out to the utility. I got as far as to &lt;code&gt;require &#x27;rubygems&#x2F;ext&#x27;&lt;&#x2F;code&gt; in order to use the &lt;code&gt;Gem::Ext::CargoBuilder&lt;&#x2F;code&gt; class, but realized that &lt;code&gt;gem&lt;&#x2F;code&gt; and &lt;code&gt;bundler&lt;&#x2F;code&gt; are just aliases to the &lt;code&gt;cargo-builder&lt;&#x2F;code&gt; branch of our &lt;code&gt;rubygems&lt;&#x2F;code&gt; repo and not a system-wide installation, I don&#x27;t have access to it within Ruby itself. It will be much easier once the PR is merged into the repository proper.&lt;&#x2F;p&gt;
&lt;p&gt;Now, there is a way using the &lt;code&gt;setup.rb&lt;&#x2F;code&gt; script in the &lt;code&gt;rubygems&lt;&#x2F;code&gt; repository, but it requires replacing your default &lt;code&gt;rubygems&lt;&#x2F;code&gt; gems. As long as this article is, it would be even longer with the caveats and restoration that would take, so I chose not to use &lt;code&gt;setup.rb&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;And now to test:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-015-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-015-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;💡 &lt;strong&gt;Click&lt;&#x2F;strong&gt; for additional notes - &lt;code&gt;&quot;true&quot;&lt;&#x2F;code&gt;?&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;EDIT&lt;&#x2F;strong&gt; - Thanks Zach! I&#x27;ve changed it to backticks 😊&lt;&#x2F;p&gt;
&lt;p&gt;The call to check whether the &lt;code&gt;ruffle&lt;&#x2F;code&gt; gem is installed is &lt;code&gt;system &#x27;gem&#x27;, &#x27;list&#x27;, &#x27;-i&#x27;, &#x27;^ruffle$&#x27;&lt;&#x2F;code&gt;. Unfortunately, the actual shell command prints &lt;code&gt;true&lt;&#x2F;code&gt; or &lt;code&gt;false&lt;&#x2F;code&gt; to stdout, so I can&#x27;t swallow it by, for example, assigning it to a variable. I&#x27;m too lazy and this post has taken too long already to add this to the list of things to figure out.&lt;&#x2F;p&gt;
&lt;p&gt;My apologies 🙇‍♂️&lt;&#x2F;p&gt;
&lt;p&gt;🙋‍♂️ RFC: what&#x27;s a better way to do this?&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;At this point, however, it&#x27;s not actually building the extension. If it were, it would print the message &lt;code&gt;&quot;Building native extensions. This could take a while...&quot;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;fixing-crate-compilation&quot;&gt;Fixing crate compilation&lt;&#x2F;h3&gt;
&lt;p&gt;There are two more things we need to change in &lt;code&gt;ruffle.gemspec&lt;&#x2F;code&gt; before it&#x27;ll work. First, we have to add &lt;code&gt;&quot;Cargo.toml&quot;&lt;&#x2F;code&gt; to &lt;code&gt;spec.extensions&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-016-rb&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-016-rb&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;But this still isn&#x27;t enough. If we run &lt;code&gt;$ rake compile&lt;&#x2F;code&gt; now, we get a cryptic error message:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-017-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-017-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The problem is that the we aren&#x27;t telling the gemspec to package the &lt;code&gt;Cargo.lock&lt;&#x2F;code&gt; file in the final &lt;code&gt;.gem&lt;&#x2F;code&gt; file, and building the crate requires a lock on the &lt;code&gt;Cargo.lock&lt;&#x2F;code&gt; file. So how do we add the lockfile to the finished gem? By adding them to the &lt;code&gt;spec.files&lt;&#x2F;code&gt; array in the gemspec. You can read more about that &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;guides.rubygems.org&#x2F;specification-reference&#x2F;#files&quot;&gt;here.&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;There are two ways we can do this:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Add the &lt;code&gt;Cargo.lock&lt;&#x2F;code&gt; and &lt;code&gt;Cargo.toml&lt;&#x2F;code&gt; files to the &lt;code&gt;git&lt;&#x2F;code&gt; history. The default logic for &lt;code&gt;spec.files&lt;&#x2F;code&gt; relies on the &lt;code&gt;git&lt;&#x2F;code&gt; history. It uses &lt;code&gt;git ls-files -z.split(&quot;\x0&quot;)&lt;&#x2F;code&gt;, which only reports files that have been added to &lt;code&gt;git&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Specifically add &lt;code&gt;[&quot;Cargo.lock&quot;, &quot;Cargo.toml&quot;, and &quot;src&#x2F;lib.rs&quot;]&lt;&#x2F;code&gt; to &lt;code&gt;spec.files&lt;&#x2F;code&gt; in the gemspec.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Since we haven&#x27;t been paying much attention to &lt;code&gt;git&lt;&#x2F;code&gt; and this is a simple enough project with no Ruby files, we&#x27;ll go with option #2. In &lt;code&gt;ruffle.gemspec&lt;&#x2F;code&gt;, find the code that assigns to &lt;code&gt;spec.files&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-018-rb&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-018-rb&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;...and replace it with this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-019-rb&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-019-rb&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We need to set the &lt;code&gt;crate-type&lt;&#x2F;code&gt; to &lt;code&gt;&quot;cdylib&quot;&lt;&#x2F;code&gt; in order to tell the Rust compiler that the output should be a shared library that can be used from other languages. As per the Rust docs on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;reference&#x2F;linkage.html&quot;&gt;Linkage&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&amp;gt; &lt;code&gt;--crate-type=cdylib&lt;&#x2F;code&gt;, &lt;code&gt;#[crate_type = &quot;cdylib&quot;]&lt;&#x2F;code&gt; - A dynamic system library will be produced. This is used when compiling a dynamic library to be loaded from another language. This output type will create &lt;code&gt;*.so&lt;&#x2F;code&gt; files on Linux, &lt;code&gt;*.dylib&lt;&#x2F;code&gt; files on macOS, and &lt;code&gt;*.dll&lt;&#x2F;code&gt; files on Windows.&lt;&#x2F;p&gt;
&lt;p&gt;So next, we add &lt;code&gt;crate-type&lt;&#x2F;code&gt; to &lt;code&gt;Cargo.toml&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-021-toml&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-021-toml&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Now we can finally count on &lt;code&gt;rake&lt;&#x2F;code&gt; to build the crate:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-022-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-022-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;💡 &lt;strong&gt;Click&lt;&#x2F;strong&gt; for additional details - what happens when we don&#x27;t set &lt;code&gt;crate-type&lt;&#x2F;code&gt;?&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;When we run &lt;code&gt;$ rake compile&lt;&#x2F;code&gt;, we get another error:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ rake compile&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# ...omitted&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Compiling ruffle v0.1.0 (&#x2F;Users&#x2F;brian&#x2F;.rbenv&#x2F;versions&#x2F;3.0.0&#x2F;lib&#x2F;ruby&#x2F;gems&#x2F;3.0.0&#x2F;gems&#x2F;ruffle-0.1.0)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   Finished release [optimized] target(s) in 0.47s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Dynamic library not found for Rust extension (in &#x2F;Users&#x2F;brian&#x2F;.rbenv&#x2F;versions&#x2F;3.0.0&#x2F;lib&#x2F;ruby&#x2F;gems&#x2F;3.0.0&#x2F;extensions&#x2F;x86_64-darwin-21&#x2F;3.0.0&#x2F;ruffle-0.1.0)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Make sure you set &amp;quot;crate-type&amp;quot; in Cargo.toml to &amp;quot;cdylib&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The error message came with instructions this time! &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ianks&#x2F;rubygems&#x2F;blob&#x2F;cargo-builder&#x2F;lib&#x2F;rubygems&#x2F;ext&#x2F;cargo_builder.rb#L287-L301&quot;&gt;Thanks, @ianks!&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;defining-the-ruffle-module-in-rust&quot;&gt;Defining the &lt;code&gt;Ruffle&lt;&#x2F;code&gt; module in Rust&lt;&#x2F;h3&gt;
&lt;p&gt;While the crate is compiling now, our tests are still failing because we haven&#x27;t actually done anything with the Rust code. Since we&#x27;ll be creating the Ruby data structures on the Rust side, we&#x27;ll use a Ruby API to interface with Ruby internals. Enter &lt;code&gt;[rb-sys](https:&#x2F;&#x2F;github.com&#x2F;ianks&#x2F;rb-sys)&lt;&#x2F;code&gt;, Rust bindings for ruby that have been automatically generated using &lt;code&gt;[rust-bindgen](https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;rust-bindgen)&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Add it under your dependencies in &lt;code&gt;Cargo.toml&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-023-toml&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-023-toml&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Next, we&#x27;ll just copy from &lt;code&gt;[rust_ruby_example&#x2F;src&#x2F;lib.rs](https:&#x2F;&#x2F;github.com&#x2F;briankung&#x2F;rust_ruby_example&#x2F;blob&#x2F;main&#x2F;src&#x2F;lib.rs)&lt;&#x2F;code&gt;, the example gem from the last post, except we&#x27;ll substitute &quot;ruffle&quot; wherever it says &quot;rust_ruby_example&quot; and &quot;shuffle&quot; wherever it says &quot;reverse.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-024-rs&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-024-rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Now we just remove the &lt;code&gt;lib&#x2F;ruffle.rb&lt;&#x2F;code&gt; file:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-026-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-026-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;💡 &lt;strong&gt;Click&lt;&#x2F;strong&gt; for additional details - why delete &lt;code&gt;lib&#x2F;ruffle.rb&lt;&#x2F;code&gt;?&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;The &lt;code&gt;respond_to&lt;&#x2F;code&gt; test won&#x27;t pass because Ruby&#x27;s &lt;code&gt;require&lt;&#x2F;code&gt; method will look in &lt;code&gt;lib&lt;&#x2F;code&gt; first and find the empty &lt;code&gt;lib&#x2F;ruffle.rb&lt;&#x2F;code&gt; file before it searches available gems (you can read more about how Ruby&#x27;s &lt;code&gt;require&lt;&#x2F;code&gt; works here: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ryanbigg.com&#x2F;2017&#x2F;11&#x2F;how-require-loads-a-gem&quot;&gt;https:&#x2F;&#x2F;ryanbigg.com&#x2F;2017&#x2F;11&#x2F;how-require-loads-a-gem&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s the proof:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ rake compile spec&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# ...omitted&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Ruffle&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  has a #shuffle method (FAILED - 1)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Failures:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  1) Ruffle has a #shuffle method&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     Failure&#x2F;Error: expect(Ruffle).to respond_to(:shuffle)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       expected Ruffle to respond to :shuffle&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     # .&#x2F;spec&#x2F;ruffle_spec.rb:5:in `block (2 levels) in &amp;lt;top (required)&amp;gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;(Note that this leaves &lt;code&gt;lib&#x2F;ruffle&#x2F;version.rb&lt;&#x2F;code&gt;, which could be confusing for anyone reading your code.)&lt;&#x2F;p&gt;
&lt;p&gt;Now, let&#x27;s run &lt;code&gt;rake spec&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-027-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-027-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We&#x27;re green! ✅ And all with Rust code.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;implementing-ruffle-shuffle&quot;&gt;Implementing &lt;code&gt;Ruffle#shuffle&lt;&#x2F;code&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Next, let&#x27;s add a test that describes the behavior of the method:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-028-rb&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-028-rb&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Technically, this could fail if the shuffled string randomly returns the original string. If this happens, you&#x27;ve won the random number generator lottery! Take a screenshot 📸&lt;&#x2F;p&gt;
&lt;p&gt;And when we run &lt;code&gt;rake spec&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-029-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-029-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Because we&#x27;ve simply copied over &lt;code&gt;rust_ruby_example&lt;&#x2F;code&gt;&#x27;s &lt;code&gt;pub_reverse&lt;&#x2F;code&gt; code, it&#x27;s just reversing the string.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s see if we can modify our &lt;code&gt;pub_shuffle&lt;&#x2F;code&gt; method in Rust to look like what we want. Right now we have:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-030-rs&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-030-rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Instead of &lt;code&gt;let shuffled = ruby_string.chars().rev().collect::&amp;lt;String&amp;gt;()&lt;&#x2F;code&gt; on line 4, we would want something like &lt;code&gt;let shuffled = ruby_string.chars().shuffle().collect::&amp;lt;String&amp;gt;()&lt;&#x2F;code&gt;. Unfortunately, there is no such method implemented on Rust&#x27;s &lt;code&gt;Iter&lt;&#x2F;code&gt; struct.&lt;&#x2F;p&gt;
&lt;p&gt;As per &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;a&#x2F;26035435&#x2F;1042144&quot;&gt;this StackOverflow answer&lt;&#x2F;a&gt;, you can use Rust&#x27;s &lt;code&gt;rand::seq::SliceRandom&lt;&#x2F;code&gt; trait to provide a &lt;code&gt;shuffle&lt;&#x2F;code&gt; method on &lt;code&gt;Vec&lt;&#x2F;code&gt;s. StackOverflow user Vladimir Matveev&#x27;s answer looks like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-031-rs&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-031-rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Shuffling a vector is a randomized operation, so we need a random number generator (RNG), and Rust doesn&#x27;t have an RNG in its standard library. The de facto standard RNG in Rust is &lt;code&gt;[rand](https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;rand)&lt;&#x2F;code&gt;. Let&#x27;s add it to our dependencies:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-032-toml&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-032-toml&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In the original code, the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;primitive.char.html&quot;&gt;&lt;code&gt;char&lt;&#x2F;code&gt;s&lt;&#x2F;a&gt; are reversed and collected into an owned &lt;code&gt;String&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-033-rs&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-033-rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;However, we need to actually mutate the &lt;code&gt;Vec&lt;&#x2F;code&gt; in place instead of using fancy functional &lt;code&gt;Iter&lt;&#x2F;code&gt; methods.&lt;&#x2F;p&gt;
&lt;p&gt;In &lt;code&gt;rust_ruby_example&lt;&#x2F;code&gt; the &lt;code&gt;input&lt;&#x2F;code&gt; goes from a Ruby &lt;code&gt;VALUE&lt;&#x2F;code&gt; type:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-034-rs&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-034-rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;To a &lt;code&gt;CString&lt;&#x2F;code&gt; type with this function call:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-035-rs&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-035-rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Finally to a Rust &lt;code&gt;String&lt;&#x2F;code&gt; type with the final function call:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-036-rs&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-036-rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We want to shuffle the characters of the string, so we&#x27;ll declare it as such and request the characters. Calling &lt;code&gt;collect()&lt;&#x2F;code&gt; charges you casts the value into the requested type signature if an &lt;code&gt;Into&lt;&#x2F;code&gt; trait is available for the type conversion:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-037-rs&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-037-rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;💡 Additional notes about &lt;code&gt;chars()&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Note that Rust&#x27;s &lt;code&gt;chars()&lt;&#x2F;code&gt; method does not handle Unicode &lt;em&gt;grapheme clusters&lt;&#x2F;em&gt; (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;briankung.dev&#x2F;2022&#x2F;02&#x2F;02&#x2F;writing-a-rust-gem-from-scratch&#x2F;#comment-273&quot;&gt;thanks, Wesley!&lt;&#x2F;a&gt;). As per Rust&#x27;s documentation on the &lt;code&gt;chars&lt;&#x2F;code&gt; method:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Remember, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;stable&#x2F;std&#x2F;primitive.char.html&quot;&gt;&lt;code&gt;char&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;s might not match your intuition about characters:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; y&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;y̆&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;    let mut&lt;&#x2F;span&gt;&lt;span&gt; chars&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; y&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;chars&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;    assert_eq!&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Some&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;&amp;#39;),&lt;&#x2F;span&gt;&lt;span&gt; chars&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;next&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;());&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt; &#x2F;&#x2F; not &amp;#39;y̆&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;    assert_eq!&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Some&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #EA76CB;&quot;&gt;\u{0306}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;&amp;#39;),&lt;&#x2F;span&gt;&lt;span&gt; chars&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;next&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;    assert_eq!&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;None&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; chars&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;next&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;blockquote&gt;
&lt;p&gt;The more or less canonical way to handle this is to use the &lt;code&gt;unicode-segmentation&lt;&#x2F;code&gt; crate, as per &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;a&#x2F;58770681&#x2F;1042144&quot;&gt;this StackOverflow answer.&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This is also a handy introduction to Unicode: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.joelonsoftware.com&#x2F;2003&#x2F;10&#x2F;08&#x2F;the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses&#x2F;&quot;&gt;The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Now we can bring the &lt;code&gt;rand&lt;&#x2F;code&gt; functionality into scope at the top of our file:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-038-rs&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-038-rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;And then call &lt;code&gt;shuffle&lt;&#x2F;code&gt; on the &lt;code&gt;chars&lt;&#x2F;code&gt; vec:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-039-rs&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-039-rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;So your function should now look like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-040-rs&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-040-rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Now we need to convert the &lt;code&gt;Vec&amp;lt;char&amp;gt;&lt;&#x2F;code&gt; to a Rust &lt;code&gt;String&lt;&#x2F;code&gt; and store its length as a &lt;code&gt;c_long&lt;&#x2F;code&gt; type, which in this case is just a type alias for &lt;code&gt;i64&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-041-rs&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-041-rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Then we construct a new &lt;code&gt;CString&lt;&#x2F;code&gt; from the shuffled Rust &lt;code&gt;String&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-042-rs&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-042-rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;And finally return the Ruby String:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-043-rs&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-043-rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;...and with that, the final function looks like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-044-rs&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-044-rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;And don&#x27;t forget to check your &lt;code&gt;Init_ruffle&lt;&#x2F;code&gt; method that actually initializes the Ruby &lt;code&gt;Ruffle&lt;&#x2F;code&gt; module and defines the method:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-045-rs&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-045-rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;(It&#x27;s unmodified from our &lt;a href=&quot;https:&#x2F;&#x2F;briankung.dev&#x2F;2022&#x2F;02&#x2F;02&#x2F;writing-a-rust-gem-from-scratch&#x2F;#copy-pasta&quot;&gt;earlier template code&lt;&#x2F;a&gt;.)&lt;&#x2F;p&gt;
&lt;p&gt;Now to recompile it and run the specs:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-046-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;11e2a18b099c4d8b60ac8b519f7cef52#file-046-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;And we&#x27;re passing!&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;I&#x27;m sure there will be a lot of patterns emerging on how to organize the code once people start creating their own Rust gems - this is by no means a definitive one, just the one I copied from @ianks&#x27;s &lt;code&gt;rust_ruby_example&lt;&#x2F;code&gt; gem. I&#x27;m a novice as well! But hopefully you got as much out of reading this as I did out of writing it. And with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rubygems&#x2F;rubygems&#x2F;pull&#x2F;5175#issuecomment-1027085401&quot;&gt;@ianks&#x27;s pull request approved and passing CI&lt;&#x2F;a&gt;, hopefully it&#x27;ll be only a matter of time before everyone gets to play with the new functionality!&lt;&#x2F;p&gt;
&lt;p&gt;The commit messages are pretty bad because it was a spike for me, but you can find all the code here: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;briankung&#x2F;ruffle&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;briankung&#x2F;ruffle&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Sneak preview: Writing Ruby gem native extensions in Rust</title>
        <published>2022-01-31T06:46:52+00:00</published>
        <updated>2022-01-31T06:46:52+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2022/01/31/sneak-preview-writing-ruby-gem-native-extensions-in-rust/"/>
        <id>https://briankung.dev/2022/01/31/sneak-preview-writing-ruby-gem-native-extensions-in-rust/</id>
        
        <content type="html" xml:base="https://briankung.dev/2022/01/31/sneak-preview-writing-ruby-gem-native-extensions-in-rust/">&lt;p&gt;&lt;em&gt;Note: anytime you see&lt;&#x2F;em&gt; 🙋‍♂️ RFC_, that&#x27;s a &quot;Request For Comments&quot; about a topic I didn&#x27;t understand or take the time to look into. Please feel free to add what you know!_&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;If this post tickles your fancy, check out the follow-up post: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;briankung.dev&#x2F;2022&#x2F;02&#x2F;02&#x2F;writing-a-rust-gem-from-scratch&#x2F;&quot;&gt;Writing a Rust gem from scratch&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In December 2021, Ian Ker-Seymer (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ianks&quot;&gt;@ianks&lt;&#x2F;a&gt;) submitted &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rubygems&#x2F;rubygems&#x2F;pull&#x2F;5175&quot;&gt;a pull request&lt;&#x2F;a&gt; to enable native extensions in Rust!&lt;&#x2F;p&gt;
&lt;p&gt;I was so excited, I had to try it out, even though it hadn&#x27;t been merged yet. A lot of maintainers are showing interest and pitching in, so I have high hopes for it being merged into main. So here are my notes on writing a Rust gem extension.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;requirements&quot;&gt;Requirements&lt;&#x2F;h2&gt;
&lt;p&gt;Requirements &#x2F; dependencies &#x2F; utilities I used and their versions on macOS Monterey v12.1 (21C52) as of 2022-01-29:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Bundler version 2.4.0.dev&lt;&#x2F;li&gt;
&lt;li&gt;gem version 3.4.0.dev&lt;&#x2F;li&gt;
&lt;li&gt;cargo 1.58.0 (f01b232bc 2022-01-19)&lt;&#x2F;li&gt;
&lt;li&gt;rustc 1.58.1 (db9d1b20b 2022-01-20)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;using-a-rubygems-fork&quot;&gt;Using a &lt;code&gt;rubygems&lt;&#x2F;code&gt; fork&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;Warning! The following is based on ianks&#x27;s development branch of Rubygems. The feature may have changed - or not exist at all - by the time you read this. I&#x27;ll modify this warning if the feature ends up being merged.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Find somewhere cozy to clone @ianks&#x27;s &lt;code&gt;cargo-builder&lt;&#x2F;code&gt; branch of &lt;code&gt;rubygems&lt;&#x2F;code&gt; and run the following:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-000-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-000-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;aliasing-your-default-rubygems&quot;&gt;Aliasing your default rubygems&lt;&#x2F;h3&gt;
&lt;p&gt;We need to be able to use the &lt;code&gt;gem&lt;&#x2F;code&gt; and &lt;code&gt;bundle&lt;&#x2F;code&gt; commands from the &lt;code&gt;cargo-builder&lt;&#x2F;code&gt; branch of &lt;code&gt;rubygems&lt;&#x2F;code&gt;. As per the directions in the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rubygems&#x2F;rubygems&#x2F;blob&#x2F;master&#x2F;CONTRIBUTING.md#getting-started&quot;&gt;&lt;code&gt;CONTRIBUTING.md&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;To run commands like &lt;code&gt;gem install&lt;&#x2F;code&gt; from the repo:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ruby -Ilib bin&#x2F;gem install&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To run commands like &lt;code&gt;bundle install&lt;&#x2F;code&gt; from the repo:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ruby bundler&#x2F;spec&#x2F;support&#x2F;bundle.rb install&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;blockquote&gt;
&lt;p&gt;But this is a hassle, so we&#x27;ll use aliases instead of typing all of this up every time. &lt;code&gt;cd&lt;&#x2F;code&gt; into your &lt;code&gt;rubygems&lt;&#x2F;code&gt; directory and alias these commands with the following:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-001-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-001-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We&#x27;re going to use the &lt;code&gt;RUBYGEMS_PATH&lt;&#x2F;code&gt; variable later on, so keep that handy! Now if you check the version numbers of your default gems, they should be as follows:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-002-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-002-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Note that these aliases won&#x27;t be present in a new terminal shell!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;compiling-an-example-gem&quot;&gt;Compiling an example gem&lt;&#x2F;h2&gt;
&lt;p&gt;We&#x27;re ready to test the functionality of a Rust-based gem. For starters, let&#x27;s use the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;briankung&#x2F;rust_ruby_example&quot;&gt;&lt;code&gt;rust_ruby_example&lt;&#x2F;code&gt; gem&lt;&#x2F;a&gt; that I&#x27;ve extracted from @ianks&#x27;s pull request:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-003-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-003-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s confirm that it does, indeed, allow us to run Rust code from Ruby.&lt;&#x2F;p&gt;
&lt;p&gt;First, we need to build the gem. We do this by pointing the &lt;code&gt;gem&lt;&#x2F;code&gt; command at a &lt;code&gt;.gemspec&lt;&#x2F;code&gt; file. Luckily, the repo has one of those:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-004-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-004-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We also explicitly name the output file, otherwise we get something like &lt;code&gt;rust_ruby_example-0.1.0.gem&lt;&#x2F;code&gt;, which is just a tad bit more awkward.&lt;&#x2F;p&gt;
&lt;p&gt;And we&#x27;re done!&lt;&#x2F;p&gt;
&lt;p&gt;...well, not exactly. As it turns out, extensions aren&#x27;t compiled until you &lt;em&gt;install&lt;&#x2F;em&gt; the gem. It makes sense that building the gem and installing the gem are two separate steps. So next we need to install it:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-005-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-005-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Firing up &lt;code&gt;cargo&lt;&#x2F;code&gt; took a minute or so on my machine.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;potential-errors&quot;&gt;Potential errors&lt;&#x2F;h4&gt;
&lt;p&gt;Speaking of &lt;code&gt;cargo&lt;&#x2F;code&gt;, if you don&#x27;t have it installed, you may see a message that looks like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-006-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-006-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This means that you don&#x27;t have cargo installed, or &lt;code&gt;rubygems&lt;&#x2F;code&gt; couldn&#x27;t find &lt;code&gt;cargo&lt;&#x2F;code&gt; in your &lt;code&gt;$PATH&lt;&#x2F;code&gt;. Make sure to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.rust-lang.org&#x2F;tools&#x2F;install&quot;&gt;install Rust&lt;&#x2F;a&gt; and come back when you&#x27;re done!&lt;&#x2F;p&gt;
&lt;p&gt;You may also see an error like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-007-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-007-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The key here being the message &lt;code&gt;&quot;No builder for extension &#x27;Cargo.toml&#x27;.&quot;&lt;&#x2F;code&gt; If that&#x27;s the case, double check your &lt;code&gt;bundler --version&lt;&#x2F;code&gt; and &lt;code&gt;gem --version&lt;&#x2F;code&gt; to make sure they match the versions above. Your current version of the &lt;code&gt;gem&lt;&#x2F;code&gt; utility is missing @ianks&#x27;s &lt;code&gt;CargoBuilder&lt;&#x2F;code&gt; addition.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;inspecting-rust-ruby-example-code&quot;&gt;Inspecting &lt;code&gt;rust_ruby_example&lt;&#x2F;code&gt; code&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;rust_ruby_example&lt;&#x2F;code&gt; includes some sample code in &lt;code&gt;src&#x2F;lib.rs&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-008-rs&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-008-rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If you&#x27;ve never seen Ruby internal code before, a few of these methods look like exactly what you&#x27;d call in C code, courtesy of a library called &lt;code&gt;[rb-sys](https:&#x2F;&#x2F;github.com&#x2F;ianks&#x2F;rb-sys)&lt;&#x2F;code&gt;. The key here is in the name of the method - &lt;code&gt;pub_reverse&lt;&#x2F;code&gt; reverses strings. Here&#x27;s where the reversal actually happens:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-009-rs&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-009-rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;There&#x27;s also an initialization function, &lt;code&gt;Init_rust_ruby_example&lt;&#x2F;code&gt;, to actually define the Ruby modules and methods. Let&#x27;s piece together what it&#x27;s doing. Here are the relevant lines for declaring a Ruby module:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-010-rs&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-010-rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;...and the rest is all adding the &lt;code&gt;reverse&lt;&#x2F;code&gt; method to the module:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-011-rs&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-011-rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Note that it needs to translate everything into Matz&#x27;s Ruby compatible data structures. That includes the module, the module function, and even the string name for the function.&lt;&#x2F;p&gt;
&lt;p&gt;(🙋‍♂️ RFC: what is the purpose of &lt;code&gt;[std::mem::tr](transmute)[an](https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;stable&#x2F;std&#x2F;mem&#x2F;fn.transmute.html)[smute](transmute)&lt;&#x2F;code&gt; here?)&lt;&#x2F;p&gt;
&lt;p&gt;💡 &lt;strong&gt;Click&lt;&#x2F;strong&gt; to read more about the purpose of &lt;code&gt;std::mem::transmute&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;From &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;briankung.dev&#x2F;2022&#x2F;02&#x2F;02&#x2F;writing-a-rust-gem-from-scratch&#x2F;#comment-274&quot;&gt;a comment I wrote on the follow up post:&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;After staring at the C header file where &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ruby&#x2F;ruby&#x2F;blob&#x2F;cb4e2cb55a59833fc4f1f6db2f3082d1ffcafc80&#x2F;include&#x2F;ruby&#x2F;internal&#x2F;method.h#L28-L99&quot;&gt;&lt;code&gt;rb_define_module_function&lt;&#x2F;code&gt; is defined&lt;&#x2F;a&gt; - I don&#x27;t know C 😰 - I think it&#x27;s necessary because Rust won&#x27;t let you pass a function pointer with arbitrary arity, but the C code just assumes that you can. Note that the last argument in &lt;code&gt;rb_define_module_function&lt;&#x2F;code&gt; is an arity indicator. So the transmutation is just ceremony to get a function pointer - any function pointer - past Rust&#x27;s type system. That&#x27;s my guess, anyway.&lt;&#x2F;p&gt;
&lt;p&gt;EDIT - Seems right! &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;_ianks&#x2F;status&#x2F;1489419634168184834&quot;&gt;https:&#x2F;&#x2F;twitter.com&#x2F;_ianks&#x2F;status&#x2F;1489419634168184834&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;trying-out-rust-ruby-example&quot;&gt;Trying out &lt;code&gt;rust_ruby_example&lt;&#x2F;code&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Alright, if you&#x27;ve seen this message:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-012-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-012-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;...you&#x27;re ready to go! Fire up IRB and require &lt;code&gt;rust_ruby_example&lt;&#x2F;code&gt; to take it for a test drive:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-013-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-013-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It reverses the string, as promised. It works!&lt;&#x2F;p&gt;
&lt;p&gt;...or does it? Let&#x27;s see if it&#x27;s really doing our bidding by modifying the code.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;adding-a-lowercase-method&quot;&gt;Adding a &lt;code&gt;lowercase&lt;&#x2F;code&gt; method&lt;&#x2F;h3&gt;
&lt;p&gt;Let&#x27;s add a &lt;code&gt;RustRubyExample#lowercase&lt;&#x2F;code&gt; method. It will be exactly the same as &lt;code&gt;RustRubyExample#reverse&lt;&#x2F;code&gt;, except it converts case-convertible text to lower case.&lt;&#x2F;p&gt;
&lt;p&gt;It should work like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-014-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-014-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;And we can confirm that it currently does not work:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-015-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-015-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;So let&#x27;s add it. Once again we need &lt;code&gt;#[no_mangle]&lt;&#x2F;code&gt; to tell the compiler not to alter the name of the function once it&#x27;s been compiled. Mangling essentially namespaces function names so there are no name collisions in the final binary. However, in our case, we want to be able to refer to it by the name we give it in C Ruby, so we don&#x27;t want our function name to be mangled&lt;&#x2F;p&gt;
&lt;p&gt;Add this block of code between the &lt;code&gt;pub_reverse&lt;&#x2F;code&gt; and &lt;code&gt;Init_rust_ruby_example&lt;&#x2F;code&gt; functions in &lt;code&gt;src&#x2F;lib.rs&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-016-rs&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-016-rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We&#x27;re also going to copy the function signature:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-017-rs&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-017-rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;(🙋‍♂️ RFC: why does this need the &lt;code&gt;_klass&lt;&#x2F;code&gt; argument?)&lt;&#x2F;p&gt;
&lt;p&gt;💡 &lt;strong&gt;Click&lt;&#x2F;strong&gt; to read more about &lt;code&gt;_klass&lt;&#x2F;code&gt; argument&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;After figuring out &lt;a href=&quot;https:&#x2F;&#x2F;briankung.dev&#x2F;2022&#x2F;01&#x2F;31&#x2F;sneak-preview-writing-ruby-gem-native-extensions-in-rust&#x2F;#purpose-of-transmute&quot;&gt;the purpose of the call to &lt;code&gt;std::mem::transmute&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, the &lt;code&gt;_klass&lt;&#x2F;code&gt; argument isn&#x27;t too confusing. It has a leading underscore because it&#x27;s unused, but the type of functions with that arity on the C side requires a receiver object for the method, even if it goes unused.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Next we take the Ruby &lt;code&gt;VALUE&lt;&#x2F;code&gt; input and cast it to a Rust string, then lowercase it using standard Rust &lt;code&gt;String&lt;&#x2F;code&gt; methods:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-018-rs&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-018-rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;...and the rest is all glue code to convert it to a C string and then to a Ruby string:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-019-rs&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-019-rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We also need to add the method to the Ruby module. We can do that by duplicating the relevant code in &lt;code&gt;Init_rust_ruby_example&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-020-rs&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-020-rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Now to build and reinstall it:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-021-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-021-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Finally, let&#x27;s test our new functionality:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-022-sh&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;briankung&#x2F;d250368e9552dc730c6608727556197d#file-022-sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Awesome!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;This is all possible due to Ian&#x27;s long, hard slog to get this into &lt;code&gt;rubygems&lt;&#x2F;code&gt; proper: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rubygems&#x2F;rubygems&#x2F;pull&#x2F;5175&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;rubygems&#x2F;rubygems&#x2F;pull&#x2F;5175&lt;&#x2F;a&gt;. This could be a hugely impactful addition to &lt;code&gt;rubygems&lt;&#x2F;code&gt; that&#x27;s been stewing since 2019 and it&#x27;s mostly been Ian&#x27;s efforts to get it there. Thanks, Ian!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;If you got this far, check out the follow-up post: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;briankung.dev&#x2F;2022&#x2F;02&#x2F;02&#x2F;writing-a-rust-gem-from-scratch&#x2F;&quot;&gt;Writing a Rust gem from scratch&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Crate of the Week second chance list</title>
        <published>2022-01-07T17:42:56+00:00</published>
        <updated>2022-01-07T17:42:56+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2022/01/07/crate-of-the-week-second-chance-list/"/>
        <id>https://briankung.dev/2022/01/07/crate-of-the-week-second-chance-list/</id>
        
        <content type="html" xml:base="https://briankung.dev/2022/01/07/crate-of-the-week-second-chance-list/">&lt;p&gt;&lt;strong&gt;TLDR&lt;&#x2F;strong&gt; - the three most upvoted crates that were never recognized as Crate of the Week in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;this-week-in-rust.org&quot;&gt;This Week in Rust&lt;&#x2F;a&gt; are &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tomaka&#x2F;glutin&quot;&gt;glutin&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rdambrosio016&#x2F;rust-cuda&quot;&gt;rust-cuda&lt;&#x2F;a&gt;, and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tomaka&#x2F;redshirt&quot;&gt;redshirt&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;The Crate of the Week is a Rust (programming language, not game) segment in the This Week in Rust newsletter that highlights a single Rust library in a given week. This helps Rust community members discover and promote crates. You can submit a crate suggestion as well as vote on crates in this &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;users.rust-lang.org&#x2F;t&#x2F;crate-of-the-week&#x2F;2704&quot;&gt;forum thread&lt;&#x2F;a&gt; by &quot;liking&quot; comments.&lt;&#x2F;p&gt;
&lt;p&gt;I was curious whether there were any crates that had never made it onto &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;this-week-in-rust.org&#x2F;&quot;&gt;this-week-in-rust.org&lt;&#x2F;a&gt; as a Crate of the Week, despite having a lot of upvotes, so I decided to take a look. I figured it would take an afternoon or so. Little did I know that it would take &lt;em&gt;many&lt;&#x2F;em&gt; afternoons for this busy stay-at-home-dad.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;methodology&quot;&gt;Methodology&lt;&#x2F;h2&gt;
&lt;p&gt;I downloaded all of the comments in the TWIR crate of the week thread as JSON via this url:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;[https:&#x2F;&#x2F;users.rust-lang.org&#x2F;t&#x2F;crate-of-the-week&#x2F;2704.json?print=true](https:&#x2F;&#x2F;users.rust-lang.org&#x2F;t&#x2F;crate-of-the-week&#x2F;2704.json?print=true)&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Note the &lt;code&gt;?print=true&lt;&#x2F;code&gt; parameter - this, combined with a &lt;code&gt;&amp;amp;page=&lt;&#x2F;code&gt; parameter lets you page through 1,000 posts in a topic thread at a time.&lt;&#x2F;p&gt;
&lt;p&gt;I then associated each url with the number of likes it had received via its parent &lt;code&gt;Post&lt;&#x2F;code&gt; and sorted them by likes in descending order.&lt;&#x2F;p&gt;
&lt;p&gt;Originally, I had meant to only compare links submitted within the same week, but eventually decided it just made more sense to look for the most popular links overall. Furthermore, I originally limited the urls to the single most clicked link in a given post, so one post would result in one link (if it had any). I regret both of those decisions, but oh well ¯\_(ツ)_&#x2F;¯&lt;&#x2F;p&gt;
&lt;p&gt;I then began the arduous process of clearing out crates of the week from the resulting list by searching the &lt;code&gt;this-week-in-rust&#x2F;content&lt;&#x2F;code&gt; folder with ripgrep, then decided to automate it with a quick Ruby script, which also turned out to be more difficult than I bargained for. Trying to recreate my Ruby code in Rust only led to more hair tearing so at this point, I&#x27;m satisfied with having manually cleared out nominated crate URLs for crate URLs with 5 or more likes.&lt;&#x2F;p&gt;
&lt;p&gt;I now have a much healthier respect for data munging. I might get back to it, but I need a break from this &quot;simple&quot; task for a little bit 😵‍💫&lt;&#x2F;p&gt;
&lt;h2 id=&quot;results&quot;&gt;Results&lt;&#x2F;h2&gt;
&lt;p&gt;...for the top 25 crates, anyway. The full results can be found here: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;raw.githubusercontent.com&#x2F;briankung&#x2F;cotw_second_chance&#x2F;main&#x2F;output.csv&quot;&gt;https:&#x2F;&#x2F;raw.githubusercontent.com&#x2F;briankung&#x2F;cotw_second_chance&#x2F;main&#x2F;output.csv&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;likes&lt;&#x2F;th&gt;&lt;th&gt;url&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;13&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tomaka&#x2F;glutin&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;tomaka&#x2F;glutin&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tomaka&#x2F;redshirt&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;tomaka&#x2F;redshirt&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rdambrosio016&#x2F;rust-cuda&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;rdambrosio016&#x2F;rust-cuda&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;kornelski&#x2F;deunicode&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;kornelski&#x2F;deunicode&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;chowdhurya&#x2F;rust-unidecode&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;chowdhurya&#x2F;rust-unidecode&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;11&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;servo&#x2F;rust-smallvec&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;servo&#x2F;rust-smallvec&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;11&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;exonum&quot;&gt;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;exonum&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;lib.rs&#x2F;crates&#x2F;async-stream&quot;&gt;https:&#x2F;&#x2F;lib.rs&#x2F;crates&#x2F;async-stream&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matthiaskrgr&#x2F;cargo-cache&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;matthiaskrgr&#x2F;cargo-cache&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;9&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;xiph&#x2F;rnnoise&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;xiph&#x2F;rnnoise&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;9&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bodil&#x2F;im-rs&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;bodil&#x2F;im-rs&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;9&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;web-view&quot;&gt;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;web-view&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rustsec&#x2F;advisory-db&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;rustsec&#x2F;advisory-db&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rustaudio&#x2F;dsp-chain&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;rustaudio&#x2F;dsp-chain&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rustaudio&#x2F;&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;rustaudio&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bminixhofer&#x2F;tractjs&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;bminixhofer&#x2F;tractjs&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bluss&#x2F;petulant-avenger-graphlibrary&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;bluss&#x2F;petulant-avenger-graphlibrary&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;shrinkwraprs&quot;&gt;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;shrinkwraprs&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;duct&quot;&gt;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;duct&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;lib.rs&#x2F;crates&#x2F;enum-unitary&quot;&gt;https:&#x2F;&#x2F;lib.rs&#x2F;crates&#x2F;enum-unitary&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;theseus-os&#x2F;theseus&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;theseus-os&#x2F;theseus&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sunfishcode&#x2F;cap-std&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;sunfishcode&#x2F;cap-std&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sof3&#x2F;include-flate&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;sof3&#x2F;include-flate&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rhysd&#x2F;cargo-husky&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;rhysd&#x2F;cargo-husky&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matklad&#x2F;once_cell&#x2F;&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;matklad&#x2F;once_cell&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;You can view my attempt to use Rust as a scripting language here: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;briankung&#x2F;cotw_second_chance&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;briankung&#x2F;cotw_second_chance&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;I initially decided to do this entirely in Rust as much as possible because it seemed like a small task suitable for learning. For instance, instead of downloading the JSON separately, I decided to download the file in Rust using tokio and reqwest. That actually went off pretty much without a hitch.&lt;&#x2F;p&gt;
&lt;p&gt;Then I got a bit sidetracked figuring out that I didn&#x27;t have to declare every field in my JSON structure before I deserialized it with serde - though I did find the fantastic &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;transform.tools&#x2F;json-to-rust-serde&quot;&gt;transform.tools&lt;&#x2F;a&gt; website to help with that. Also serde and its documentation seemed really opaque to me at first - was I supposed to implement &lt;code&gt;Deserialize&lt;&#x2F;code&gt;, and if so, then how? Finally, I pointed the right &lt;code&gt;serde_json&lt;&#x2F;code&gt; method at the JSON data and carried on. I originally wanted to make sure that the posts were in order and grouped by week, but I found the &lt;code&gt;time&lt;&#x2F;code&gt; crate to be similarly difficult to find examples for, and a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;time-rs.github.io&#x2F;book&#x2F;&quot;&gt;bewilderingly empty book&lt;&#x2F;a&gt; left me delaying the &lt;code&gt;time&lt;&#x2F;code&gt; related features. Ironically, I didn&#x27;t group the posts by week in the end, anyway, so I could have ignored the timestamps.&lt;&#x2F;p&gt;
&lt;p&gt;And finally when I thought I had gotten something halfway acceptable, I still found a good deal of crates that had already been CotW winners in my filtered list of crates. &quot;How many incorrect entries could there be?&quot; I wondered naively, and then began to search &lt;code&gt;&quot;crate_name site:this-week-in-rust.org&quot;&lt;&#x2F;code&gt; on Google and discovered that the answer to my question was &quot;quite a lot, actually.&quot; I ended up using ripgrep in the command line to search the &lt;code&gt;this-week-in-rust&lt;&#x2F;code&gt; repo, then got frustrated and jumped ship back to Ruby to automate it. After writing a script in my native tongue of Ruby, this is how I felt:&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;images&#x2F;60iq8m.jpg&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;images&#x2F;60iq8m.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;figcaption&gt;
&lt;p&gt;Update - I rewrote the logic in Rust, after all.&lt;&#x2F;p&gt;
&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;However, the biggest problem was that I underestimated how difficult it would be to beat the data I had into the proper shape. As it turns out, data munging is not a simple task. Comments aren&#x27;t uniform, URLs aren&#x27;t uniform, and even issues of This Week in Rust aren&#x27;t uniform. At one point I was searching for a markdown header like &lt;code&gt;&quot;# Crate of the Week&quot;&lt;&#x2F;code&gt; and discovered that one issue had it as &lt;code&gt;&quot;# Crate &amp;amp; Quote of the Week&quot;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;In the end, I did finally use a lot of libraries I&#x27;d been wanting to use and got a hang of a bit more corners of the Rust world, so it was still a worthwhile endeavor. While there must be smarter ways to handle this problem, I&#x27;ve run out of enthusiasm for it, so I&#x27;m putting it on the backburner. You&#x27;re welcome to take a crack at it yourself! I&#x27;d love to hear about it if you do.&lt;&#x2F;p&gt;
&lt;p&gt;Oh, and...don&#x27;t forget to nominate crates in the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;users.rust-lang.org&#x2F;t&#x2F;crate-of-the-week&#x2F;2704&quot;&gt;Crate of the Week thread!&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Building a CEDICT parser in Rust with Nom</title>
        <published>2021-12-07T07:22:04+00:00</published>
        <updated>2021-12-07T07:22:04+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2021/12/07/building-a-cedict-parser-in-rust-with-nom/"/>
        <id>https://briankung.dev/2021/12/07/building-a-cedict-parser-in-rust-with-nom/</id>
        
        <content type="html" xml:base="https://briankung.dev/2021/12/07/building-a-cedict-parser-in-rust-with-nom/">&lt;p&gt;The &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;cc-cedict.org&#x2F;wiki&#x2F;format:syntax&quot;&gt;CEDICT format&lt;&#x2F;a&gt; is a simple, creative commons-licensed file format for Chinese&#x2F;English dictionaries. While Mandarin-only CEDICT parsers abound, there is basically no support for Cantonese jyutping in the English-speaking programming world. As someone who would have liked to use Cantonese pronunciations in my programs, at first I was stuck. I considered adding jyutping support to an existing parser, but the example parser I found seemed difficult to extend in such a way. I had also never hand-written a parser before, other than some very simple tutorials.&lt;&#x2F;p&gt;
&lt;p&gt;I forgot how I stumbled across it, but that&#x27;s when I found &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;nom&#x2F;latest&#x2F;nom&#x2F;&quot;&gt;nom&lt;&#x2F;a&gt;, a &quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Parser_combinator&quot;&gt;parser combinator&lt;&#x2F;a&gt;&quot; library whose motto is &quot;eating data byte by byte.&quot; Reading the documentation, I found that I could actually understand &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;nom&#x2F;latest&#x2F;nom&#x2F;#example&quot;&gt;the example code&lt;&#x2F;a&gt; for parsing a hexadecimal number into a color code.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;images&#x2F;nom.png&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;images&#x2F;nom.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;em&gt;nom, eating data byte by byte&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;What are parser combinators? I had never really looked into the term before this, assuming, as usual with topics in programming, that it was above me (this is the same cursed reason I avoided doing computer science in college). It turns out that they are a way to construct parsers like Lego blocks, piece by piece, until you have pieces that have the semantic meanings that you want, and can manipulate as you please.&lt;&#x2F;p&gt;
&lt;p&gt;The basic building blocks of parser combinators are as simple as commanding the computer to recognize (and separate) alphabetic characters, white spaces, or numerical characters. They get more complicated when you combine them, e.g. in English you would say &quot;take as many alphabetic characters as possible then a number, and we&#x27;ll call that a &lt;code&gt;syllable&lt;&#x2F;code&gt;. In this spot between the brackets, there may be many &lt;code&gt;syllables&lt;&#x2F;code&gt; so take as many &lt;code&gt;syllables&lt;&#x2F;code&gt; as you can until you encounter the end bracket.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;After &lt;code&gt;nom&lt;&#x2F;code&gt; faithfully eats and sorts bytes for me, I get to store them into meaningful data structures.&lt;&#x2F;p&gt;
&lt;p&gt;Enough pseudo code, here&#x27;s the Rust code (using &lt;code&gt;nom 6.1.2&lt;&#x2F;code&gt;) I used to parse the CEDICT entries. We&#x27;re looking to parse the following format:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;你好嗎 你好吗 [ni3 hao3 ma5] {nei5 hou2 maa1} &#x2F;how are you?&#x2F; # CEDICT also supports comments&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There are 5 sections delimited by spaces:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Traditional Chinese characters&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Simplified Chinese characters&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Pinyin, itself delimited by square brackets&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Jyutping, delimited by squiggly brackets, an addition to the CEDICT format by &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;cantonese.org&#x2F;&quot;&gt;Cantonese.org&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;English language definitions delimited by forward slashes&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;…and comments, though I&#x27;m unsure if they&#x27;re supported at the end of the line as written. I&#x27;ll skip the comments for now.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;While parser combinators are easy to write from bottom to top, it may be easiest to understand them top down - I&#x27;ll start at the highest level of abstraction and gradually drill down into the details. Another bonus of parser combinators - it&#x27;s a joy to read them afterward, even after a few months!&lt;&#x2F;p&gt;
&lt;p&gt;So here&#x27;s the parser for a &lt;code&gt;CedictEntry&lt;&#x2F;code&gt;, the Rust struct I&#x27;m using to store data about a single entry&#x27;s various parts:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; cedict_entry&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;&quot;&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; IResult&lt;&#x2F;span&gt;&lt;span style=&quot;color: #04A5E5;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; CedictEntry&lt;&#x2F;span&gt;&lt;span style=&quot;color: #04A5E5;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; traditional&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; not_whitespace&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt; character&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;complete&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;space1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; simplified&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; not_whitespace&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt; character&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;complete&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;space1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; pinyin&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; pinyin&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt; character&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;complete&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;space1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; jyutping&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt; combinator&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;opt&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;jyutping&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)(&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt; character&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;complete&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;space0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; definitions&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; definitions&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;    Ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;((&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;        CedictEntry&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            traditional&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; traditional&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;into&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            simplified&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; simplified&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;into&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            pinyin&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            jyutping&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            definitions&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;        },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;    ))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let&#x27;s start with the function signature:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; cedict_entry&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;&quot;&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; IResult&lt;&#x2F;span&gt;&lt;span style=&quot;color: #04A5E5;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; CedictEntry&lt;&#x2F;span&gt;&lt;span style=&quot;color: #04A5E5;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is a function definition in Rust declaring a function &lt;code&gt;cedict_entry&lt;&#x2F;code&gt; that takes an input &lt;code&gt;i&lt;&#x2F;code&gt; of type &lt;code&gt;&amp;amp;str&lt;&#x2F;code&gt; and returns nom&#x27;s &lt;code&gt;IResult&lt;&#x2F;code&gt; type, which itself contains &lt;code&gt;&amp;amp;str&lt;&#x2F;code&gt; and a &lt;code&gt;CedictEntry&lt;&#x2F;code&gt; if all goes well. If all doesn&#x27;t go well, it will return an error, which you can see in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;nom&#x2F;latest&#x2F;nom&#x2F;type.IResult.html&quot;&gt;&lt;code&gt;IResult&lt;&#x2F;code&gt;&#x27;s type definition&lt;&#x2F;a&gt;. The &lt;code&gt;&amp;amp;str&lt;&#x2F;code&gt; types here are important because nom attempts to be zero-copy for performance reasons - the &lt;code&gt;&amp;amp;str&lt;&#x2F;code&gt; type is immutable and does not allocate memory, serving only as a read-only window into data already loaded into memory.&lt;&#x2F;p&gt;
&lt;p&gt;The main body of the function is &lt;em&gt;almost&lt;&#x2F;em&gt; readable as pseudo-code:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; traditional&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; not_whitespace&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt; character&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;complete&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;space1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; simplified&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; not_whitespace&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt; character&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;complete&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;space1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; pinyin&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; pinyin&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt; character&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;complete&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;space1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; jyutping&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt; combinator&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;opt&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;jyutping&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)(&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt; character&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;complete&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;space0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; definitions&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; definitions&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This takes advantage of a few Rust features that come together nicely. First, &lt;code&gt;let&lt;&#x2F;code&gt; statements can do destructuring assignment. So if a function returns a tuple &lt;code&gt;(1, 2)&lt;&#x2F;code&gt;, you can &lt;code&gt;let (a, b) = (1, 2)&lt;&#x2F;code&gt; and &lt;code&gt;a&lt;&#x2F;code&gt; will be equal to &lt;code&gt;1&lt;&#x2F;code&gt; and &lt;code&gt;b&lt;&#x2F;code&gt; will be equal to &lt;code&gt;2&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Second, Rust emphasizes safety and these parsers may fail, so we have to handle it. In Rust, expected failures are captured in the type system, specifically the &lt;code&gt;Result&lt;&#x2F;code&gt; type, which allow you to either extract the value or handle the error without the program blowing up and panicking. Parsers in nom return an &lt;code&gt;IResult&lt;&#x2F;code&gt;, which is a custom &lt;code&gt;Result&lt;&#x2F;code&gt; type. When the parsers fail, nom will default to returning a &lt;code&gt;nom::ErrorKind&lt;&#x2F;code&gt;. When they succeed, nom parsers will return a tuple of two elements, the first being the remaining input and the second being the result of the parsing. So if you were parsing &lt;code&gt;&quot;abc&quot;&lt;&#x2F;code&gt; with a parser combinator that looked for the character &lt;code&gt;&quot;a&quot;&lt;&#x2F;code&gt;, for example, it might look something like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; letter_a_parser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt; bytes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;complete&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;tag&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;a&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; result&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; letter_a_parser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;abc&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# result&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;bc&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;a&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;But what happens in this code when one of these function calls returns an error? Is it just stored in the variables declared in the &lt;code&gt;let&lt;&#x2F;code&gt; statement? That&#x27;s where the question mark at the end of the line comes into play, Rust&#x27;s third salient feature. The question mark is a shortcut for saying, &quot;if the Result of an expression is a valid value, the expression evaluates as that value. Otherwise if the Result is an error, then have not just the expression, but the entire calling function return the error.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;That way we can have our &lt;code&gt;let&lt;&#x2F;code&gt; tuples and our errors, too. 🍰&lt;&#x2F;p&gt;
&lt;p&gt;Finally, we have the code that actually stores the captured data in a struct:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;((&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;    CedictEntry&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        traditional&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; traditional&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;into&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        simplified&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; simplified&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;into&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        pinyin&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        jyutping&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        definitions&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;Ok&lt;&#x2F;code&gt; is a variant of the &lt;code&gt;Result&lt;&#x2F;code&gt; &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;web.mit.edu&#x2F;rust-lang_v1.25&#x2F;arch&#x2F;amd64_ubuntu1404&#x2F;share&#x2F;doc&#x2F;rust&#x2F;html&#x2F;book&#x2F;first-edition&#x2F;enums.html&quot;&gt;enum&lt;&#x2F;a&gt;, indicating that the function executed properly. The function returns an &lt;code&gt;Ok&lt;&#x2F;code&gt; containing the rest of the input, &lt;code&gt;i&lt;&#x2F;code&gt;, so that the next parser can have a go at the input, and a &lt;code&gt;CedictEntry&lt;&#x2F;code&gt; representing, well, the parsed Cedict entry. If anything &lt;em&gt;does&lt;&#x2F;em&gt; go wrong, it will return an &lt;code&gt;Err&lt;&#x2F;code&gt;, which will need to be handled at the site of the function call.&lt;&#x2F;p&gt;
&lt;p&gt;Now, a few of the parsers I used in the body of the function were provided by nom: &lt;code&gt;not_whitespace&lt;&#x2F;code&gt;, &lt;code&gt;character::complete::space1&lt;&#x2F;code&gt;, and &lt;code&gt;character::complete::space0&lt;&#x2F;code&gt;, for instance. As mentioned before, &lt;code&gt;not_whitespace&lt;&#x2F;code&gt; will match any character that isn&#x27;t whitespace, whereas &lt;code&gt;space1&lt;&#x2F;code&gt; will match a single space and &lt;code&gt;space0&lt;&#x2F;code&gt; will match zero or one space.&lt;&#x2F;p&gt;
&lt;p&gt;But a few of these are custom parsers that I wrote from nom&#x27;s more basic building blocks: &lt;code&gt;pinyin&lt;&#x2F;code&gt;, &lt;code&gt;jyutping&lt;&#x2F;code&gt;, and &lt;code&gt;definitions&lt;&#x2F;code&gt;. Let&#x27;s take a look at those.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-pinyin-jyutping-parsers&quot;&gt;The pinyin &#x2F; jyutping parsers&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1️⃣ 你好嗎 2️⃣ 你好吗 3️⃣ [ni3 hao3 ma5] 4️⃣ {nei5 hou2 maa1} 5️⃣ &#x2F;how are you?&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We managed to get by using nom&#x27;s builtin &lt;code&gt;not_whitespace&lt;&#x2F;code&gt; parser for 1️⃣ and 2️⃣ (as labeled above). Basically, we expect the start of the line to be characters, then a space, then more characters of a different sort. However, we can&#x27;t simply limit it to Han Unicode characters because some of the characters in the dictionary involve alphanumeric characters. In the interests of simplicity, I opted for a parser that simply matches any non-whitespace character for the first two.&lt;&#x2F;p&gt;
&lt;p&gt;For number 3️⃣, however, we&#x27;re going to need to do things a little differently. I&#x27;d like to be able to retain specific information about each syllable instead of just grabbing the entire string like I did with the Chinese characters, so the parser is more complicated. Here&#x27;s the parser for &lt;code&gt;pinyin&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; pinyin&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;&quot;&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; IResult&lt;&#x2F;span&gt;&lt;span style=&quot;color: #04A5E5;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; Option&lt;&#x2F;span&gt;&lt;span style=&quot;color: #04A5E5;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Vec&lt;&#x2F;span&gt;&lt;span style=&quot;color: #04A5E5;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Syllable&lt;&#x2F;span&gt;&lt;span style=&quot;color: #04A5E5;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    # &lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Here&lt;&#x2F;span&gt;&lt;span&gt; we split the pronunciations out from their square bracket delimiters&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;rest&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;, (&lt;&#x2F;span&gt;&lt;span&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; pronunciations&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;))&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt; sequence&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;tuple&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;((&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;        bytes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;complete&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;tag&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;[&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;        combinator&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;opt&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;bytes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;complete&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;is_not&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;]&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;        bytes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;complete&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;tag&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;]&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;    ))(&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    # &lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Here&lt;&#x2F;span&gt;&lt;span&gt; we handle the case&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt; where&lt;&#x2F;span&gt;&lt;span&gt; there&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;s&lt;&#x2F;span&gt;&lt;span&gt; nothing between the brackets&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;    if let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; Some&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;pronunciations&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; pronunciations&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; syllables&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; syllables&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;pronunciations&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;        Ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;((&lt;&#x2F;span&gt;&lt;span&gt;rest&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; Some&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;syllables&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt; else&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;        Ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;((&lt;&#x2F;span&gt;&lt;span&gt;rest&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; None&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let&#x27;s talk about this in detail, starting again with the function signature:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; pinyin&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;&quot;&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; IResult&lt;&#x2F;span&gt;&lt;span style=&quot;color: #04A5E5;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; Option&lt;&#x2F;span&gt;&lt;span style=&quot;color: #04A5E5;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Vec&lt;&#x2F;span&gt;&lt;span style=&quot;color: #04A5E5;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Syllable&lt;&#x2F;span&gt;&lt;span style=&quot;color: #04A5E5;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This takes a &lt;code&gt;&amp;amp;str&lt;&#x2F;code&gt; and returns an &lt;code&gt;IResult&amp;lt;&amp;amp;str, Option&amp;lt;Vec&amp;lt;Syllable&amp;gt;&amp;gt;&amp;gt;&lt;&#x2F;code&gt;. The &lt;code&gt;IResult&lt;&#x2F;code&gt; returns a tuple of &lt;code&gt;(&amp;amp;str, Option&amp;lt;Vec&amp;lt;Syllable&amp;gt;&amp;gt;&lt;&#x2F;code&gt;. In the case where we have parsed a valid line such as the one above, &lt;code&gt;&amp;amp;str&lt;&#x2F;code&gt; is a reference to the remainder of the input - in this case, it would be parts 4️⃣ and 5️⃣ as shown below:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;quot; {nei5 hou2 maa1} &#x2F;how are you?&#x2F;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And the &lt;code&gt;Option&amp;lt;Vec&amp;lt;Syllable&amp;gt;&amp;gt;&lt;&#x2F;code&gt; resulting from the &lt;code&gt;pinyin&lt;&#x2F;code&gt; parser would look like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Some&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;([&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;    Syllable&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        pronunciation&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;ni&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        tone&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;3&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;    Syllable&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        pronunciation&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;hao&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        tone&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;3&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;em&gt;(Note that if there were no valid syllables between the brackets it would result in a &lt;code&gt;None&lt;&#x2F;code&gt; return type instead of a &lt;code&gt;Some&lt;&#x2F;code&gt; containing a &lt;code&gt;Vec&lt;&#x2F;code&gt;. Such is the nature of the &lt;code&gt;Option&lt;&#x2F;code&gt; &lt;code&gt;Enum&lt;&#x2F;code&gt;.)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;First, we need to separate the pronunciations from their brackets, which is what this chunk of code does:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; 0️⃣ &lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;rest&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;, (&lt;&#x2F;span&gt;&lt;span&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; pronunciations&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;))&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt; sequence&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;tuple&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;((&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;    1️⃣ &lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;bytes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;complete&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;tag&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;[&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;    2️⃣ &lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;combinator&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;opt&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;bytes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;complete&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;is_not&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;]&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;&quot;&gt;    3️⃣ &lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;bytes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;complete&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;tag&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;]&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;))(&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I&#x27;m using &lt;code&gt;sequence::tuple&lt;&#x2F;code&gt;, which is a built-in nom parser that takes a tuple of parser combinators and returns a tuple of the rest of the output and an inner tuple of all of the components we ask for. The tuple we supplied included:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;1️⃣ a parser for the opening bracket of the pinyin,&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;2️⃣ a parser for any bytes that are not equal to &lt;code&gt;&quot;]&quot;&lt;&#x2F;code&gt;, made optional via nom&#x27;s built-in parser, &lt;code&gt;combinator::opt&lt;&#x2F;code&gt;, and&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;3️⃣ the ending bracket.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;We expect the output in the case of a successful parse to contain the rest of the input string, 0️⃣, followed by a tuple of &lt;code&gt;(1️⃣, 2️⃣, and 3️⃣)&lt;&#x2F;code&gt;, of which we only retain 2️⃣. In Rust, any variable beginning with an underscore tells the compiler we won&#x27;t be using it, and it is a compile time warning if either an underscored variable &lt;em&gt;is&lt;&#x2F;em&gt; used, or if a non-underscored variable goes _un_used.&lt;&#x2F;p&gt;
&lt;p&gt;By the end of this, we should have two variables declared: &lt;code&gt;rest&lt;&#x2F;code&gt;, which is the &lt;a href=&quot;https:&#x2F;&#x2F;briankung.dev&#x2F;2021&#x2F;12&#x2F;07&#x2F;building-a-cedict-parser-in-rust-with-nom&#x2F;#rest-of-the-input&quot;&gt;rest of the input&lt;&#x2F;a&gt;, and &lt;code&gt;pronunciations&lt;&#x2F;code&gt;, which is whatever was contained between the two square brackets - in this case &lt;code&gt;&quot;ni3 hao3 ma5&quot;&lt;&#x2F;code&gt;. Now to extract the individual syllables.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;if let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; Some&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;pronunciations&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; pronunciations&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; syllables&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; syllables&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;pronunciations&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;    Ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;((&lt;&#x2F;span&gt;&lt;span&gt;rest&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; Some&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;syllables&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt; else&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;    Ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;((&lt;&#x2F;span&gt;&lt;span&gt;rest&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; None&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We then check if pronunciations is a &lt;code&gt;None&lt;&#x2F;code&gt; type indicating that it didn&#x27;t find what you were looking for, or a &lt;code&gt;Some&lt;&#x2F;code&gt; type which includes the combinator results you asked for. If the result is &lt;code&gt;Some(pronunciations)&lt;&#x2F;code&gt; then we punt it down the line to the &lt;code&gt;syllables&lt;&#x2F;code&gt; parser combinator:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;&#x2F;&#x2F;&#x2F; takes a series of possibly undelimited syllables such as &amp;quot;ni3hao3&amp;quot; and returns a Vec of Syllables&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; syllables&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;&quot;&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; IResult&lt;&#x2F;span&gt;&lt;span style=&quot;color: #04A5E5;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; Vec&lt;&#x2F;span&gt;&lt;span style=&quot;color: #04A5E5;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Syllable&lt;&#x2F;span&gt;&lt;span style=&quot;color: #04A5E5;&quot;&gt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;    multi&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;many0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;syllable&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)(&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; syllable&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;&quot;&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; IResult&lt;&#x2F;span&gt;&lt;span style=&quot;color: #04A5E5;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; Syllable&lt;&#x2F;span&gt;&lt;span style=&quot;color: #04A5E5;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;rest&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;, (&lt;&#x2F;span&gt;&lt;span&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; pronunciation&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; tone&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;))&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt; sequence&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;tuple&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;((&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;        character&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;complete&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;space0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;        character&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;complete&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;alpha1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;        character&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;complete&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;digit0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;    ))(&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;    Ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;((&lt;&#x2F;span&gt;&lt;span&gt;rest&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; Syllable&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;pronunciation&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; tone&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here, I&#x27;ve broken syllables down into two separate functions, but we could easily inline the &lt;code&gt;syllable&lt;&#x2F;code&gt; parser. We start out with &lt;code&gt;multi::many0&lt;&#x2F;code&gt; which will match zero or more &lt;code&gt;syllable&lt;&#x2F;code&gt; parsers. Within the &lt;code&gt;syllable&lt;&#x2F;code&gt; parser we can see another &lt;code&gt;sequence::tuple&lt;&#x2F;code&gt; parser, which we are supplying with &lt;code&gt;space0&lt;&#x2F;code&gt;, &lt;code&gt;alpha1&lt;&#x2F;code&gt;, and &lt;code&gt;digit0&lt;&#x2F;code&gt;. Translated to English, this would match against zero or more spaces, then one or more alphabetic ASCII characters, then zero or more ASCII numerical characters, representing any leading whitespace, the pronunciation, and finally the tone (see more about tones in Mandarin &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Standard_Chinese_phonology#Tones&quot;&gt;here&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;If that&#x27;s fine, we return the rest of the input to the &lt;code&gt;multi::many0&lt;&#x2F;code&gt; parser, as well as a new &lt;code&gt;Syllable&lt;&#x2F;code&gt; struct populated with the pronunciation and the tone, then do it over and over again until the &lt;code&gt;syllable&lt;&#x2F;code&gt; parser stops matching. Finally, we&#x27;re left with our &lt;code&gt;Vec&lt;&#x2F;code&gt; of &lt;code&gt;Syllable&lt;&#x2F;code&gt; structs, as captured in this unit test:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;#&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;test&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; test_parse_syllables&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;    assert_eq!&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;        syllables&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;ni3hao3&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;        Ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;((&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;            &amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;            vec!&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;[&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;                Syllable&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;ni&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;3&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;                Syllable&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;hao&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;3&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;            ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;        ))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;    );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Thankfully, we can do much the same thing to handle the Cantonese jyutping pronunciations, just by changing the delimiters:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; jyutping&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;&quot;&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; IResult&lt;&#x2F;span&gt;&lt;span style=&quot;color: #04A5E5;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; Vec&lt;&#x2F;span&gt;&lt;span style=&quot;color: #04A5E5;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;Syllable&lt;&#x2F;span&gt;&lt;span style=&quot;color: #04A5E5;&quot;&gt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;rest&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; pronunciations&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt; sequence&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;delimited&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;        bytes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;complete&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;tag&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;{&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;        bytes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;complete&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;is_not&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;}&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;        bytes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;&quot;&gt;complete&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;tag&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;}&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;    )(&lt;&#x2F;span&gt;&lt;span&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; syllables&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; syllables&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;pronunciations&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;    Ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;((&lt;&#x2F;span&gt;&lt;span&gt;rest&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; syllables&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Hopefully that helps explain this particular use case of nom in Rust. Also, if I’ve made any mistakes in my explanations, please let me know! I’m new both to parsers and to Rust. As a novice to writing parsers, I found it very approachable, if a bit mystifying which parsers to use, at first.&lt;&#x2F;p&gt;
&lt;p&gt;On that note, nom divides its parser combinators into a couple major categories. There&#x27;s more to nom, and I&#x27;ve only just begun to explore it, but my mental map of the combinators are bytes versus characters, complete vs streaming, collections, and control flow combinators. I&#x27;ve mapped them out below:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;bytes vs characters - literally represented by &lt;code&gt;nom::bytes&lt;&#x2F;code&gt; vs &lt;code&gt;nom::character&lt;&#x2F;code&gt;. For when you need to parse at the byte level vs characters. The distinction can be a little fuzzy to me.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;complete vs streaming - the above modules each split into &lt;code&gt;complete&lt;&#x2F;code&gt; and &lt;code&gt;streaming&lt;&#x2F;code&gt; versions for when you have to handle streaming input versus when you have the entire input data at your disposal.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;collections - the &lt;code&gt;nom::multi&lt;&#x2F;code&gt; module will give you parsers for handling repetitive data. We used this module to handle multiple syllables in pinyin and jyutping.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;control flow - I think of &lt;code&gt;nom::branch&lt;&#x2F;code&gt; and &lt;code&gt;nom::combinator&lt;&#x2F;code&gt; as being control flow&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Sometimes the hardest thing is finding the right parser combinator. For that, there is now a handy guide: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Geal&#x2F;nom&#x2F;blob&#x2F;main&#x2F;doc&#x2F;choosing_a_combinator.md&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;Geal&#x2F;nom&#x2F;blob&#x2F;main&#x2F;doc&#x2F;choosing_a_combinator.md&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Note that there are many more modules that I haven&#x27;t used that look like they would come in handy, such as &lt;code&gt;nom::number&lt;&#x2F;code&gt; for parsing numbers and &lt;code&gt;nom::recipes&lt;&#x2F;code&gt;, which might have saved me a good amount of time!&lt;&#x2F;p&gt;
&lt;p&gt;Happy parsing!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;additional-links&quot;&gt;Additional Links&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Geal&#x2F;nom&quot;&gt;nom on GitHub&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;nom&#x2F;7.1.0&#x2F;nom&#x2F;&quot;&gt;nom docs on docs.rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gitter.im&#x2F;Geal&#x2F;nom&quot;&gt;nom on Gitter.im chat&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;benkay86&#x2F;nom-tutorial&quot;&gt;benkay86&#x27;s handy tutorial (nom v5)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;briankung&#x2F;cccedict&quot;&gt;briankung&#x2F;cccedict parser on GitHub&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;cc-cedict.org&#x2F;wiki&#x2F;format:syntax&quot;&gt;The CC-CEDICT format&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.mdbg.net&#x2F;chinese&#x2F;dictionary?page=cedict&quot;&gt;CC-CEDICT download page&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;cantonese.org&#x2F;download.html&quot;&gt;CC-Canto download page&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Contributing to Artichoke in Rust</title>
        <published>2021-11-20T22:30:09+00:00</published>
        <updated>2021-11-20T22:30:09+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2021/11/20/contributing-to-artichoke-in-rust/"/>
        <id>https://briankung.dev/2021/11/20/contributing-to-artichoke-in-rust/</id>
        
        <content type="html" xml:base="https://briankung.dev/2021/11/20/contributing-to-artichoke-in-rust/">&lt;p&gt;Yesterday, I eked out a bit of time to contribute to Artichoke in Rust, in no small part due to the maintainer &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lopopolo&quot;&gt;@lopopolo&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;p&gt;[![Brian Kung (he&#x2F;him&#x2F;his): Hi there! I&#x27;m a rubyist learning Rust&lt;&#x2F;p&gt;
&lt;div&gt;&lt;&#x2F;div&gt;
lopopolo: Welcome to the party
&lt;div&gt;&lt;&#x2F;div&gt;
Brian Kung: I&#x27;d like to contribute if possible someday 😊
&lt;div&gt;&lt;&#x2F;div&gt;
lopopolo: Yay
&lt;div&gt;&lt;&#x2F;div&gt;
lopopolo: If you&#x27;re thinking someday might be today (🤩), how does this ticket look? https:&#x2F;&#x2F;github.com&#x2F;artichoke&#x2F;artichoke&#x2F;issues&#x2F;1500](&#x2F;assets&#x2F;images&#x2F;screen-shot-2021-11-20-at-4.45.32-pm.png)](&#x2F;assets&#x2F;images&#x2F;screen-shot-2021-11-20-at-4.45.32-pm.png)
&lt;figcaption&gt;
&lt;p&gt;@lopopolo was very welcoming!&lt;&#x2F;p&gt;
&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;Artichoke is an implementation of Ruby written in the Rust programming language. The issue I worked on was to expose a newly stabilized method in Artichoke&#x27;s implementation of the Ruby String class. In Rust, strings are represented as Vectors of &lt;code&gt;u8&lt;&#x2F;code&gt; bytes which are guaranteed to be valid UTF-8 sequences. As of Rust version 1.56.0, the compiler stabilized the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;stable&#x2F;std&#x2F;vec&#x2F;struct.Vec.html#method.shrink_to&quot;&gt;Vec::shrink_to&lt;&#x2F;a&gt; method, which allows you to reduce the amount of memory a Vec takes, down to a lower bound, which you supply. So if you have a String and it has allocated 4 bytes, but it&#x27;s only taking up 1 byte, you can &lt;code&gt;string.shrink_to(2)&lt;&#x2F;code&gt; to reduce its size to no less than 2 bytes. Here&#x27;s that same scenario in code:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; string&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; String&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;with_capacity&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;string&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;extend&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;1&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;chars&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;assert_eq!&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;string&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;capacity&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(),&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;string&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;shrink_to&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;assert!&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;string&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;capacity&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; &amp;gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;string&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;shrink_to&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;assert!&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;string&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;capacity&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt; &amp;gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FE640B;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;(&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;play.rust-lang.org&#x2F;?version=stable&amp;amp;mode=debug&amp;amp;edition=2018&amp;amp;gist=90112a3377f9d4a92f1c031f2b3bfc83&quot;&gt;Rust Playground Link&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;
&lt;p&gt;The code I worked on exposed the same methods on Artichoke&#x27;s String classes: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;artichoke&#x2F;artichoke&#x2F;pull&#x2F;1505&#x2F;files&quot;&gt;Implements `shrink_to` on `spinoso_string::String` by briankung · Pull Request #1505 · artichoke&#x2F;artichoke&lt;&#x2F;a&gt;. The actual code, excluding the doctests, was very minimal:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;#&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;inline&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;pub fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; shrink_to&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D20F39;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E64553;&quot;&gt; min_capacity&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt; usize&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D20F39;&quot;&gt;    self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;buf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #179299;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;shrink_to&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;min_capacity&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;figure&gt;
&lt;p&gt;[![lopopolo: woohoo! this looks great&lt;&#x2F;p&gt;
&lt;div&gt;&lt;&#x2F;div&gt;
Brian Kung (he&#x2F;him&#x2F;his): Thanks for the push! Feels good to contribute 💪😂
&lt;div&gt;&lt;&#x2F;div&gt;
lopopolo: 🎉
&lt;div&gt;&lt;&#x2F;div&gt;
lopopolo: I left one ask for some changes. Since we&#x27;ve added a new API, let&#x27;s bump the version of \`spinoso-string\`.
&lt;div&gt;&lt;&#x2F;div&gt;
Brian Kung: sounds good](&#x2F;assets&#x2F;images&#x2F;screen-shot-2021-11-20-at-4.46.04-pm.png)](&#x2F;assets&#x2F;images&#x2F;screen-shot-2021-11-20-at-4.46.04-pm.png)
&lt;figcaption&gt;
&lt;p&gt;After a few tweaks, my PR was good to go!&lt;&#x2F;p&gt;
&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;But what I liked about this was how &lt;em&gt;easy&lt;&#x2F;em&gt; @lopopolo made it to contribute! From giving me the initial nudge and motivation to build Artichoke locally for the first time to the extensive guidance in the issue, it was a great way to get some open source experience on a non-trivial Rust project. I can&#x27;t recommend it enough. In fact, I can point you to a few issues that could use a similar treatment:&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;artichoke&#x2F;artichoke&#x2F;issues?q=is%3Aissue+is%3Aopen+shrink_to&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;images&#x2F;screen-shot-2021-11-20-at-22.20.48.png&quot; alt=&quot;Image of similar issues on artichoke ruby&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;figcaption&gt;
&lt;p&gt;These would require basically the same code changes as the above, and they are still open as of Saturday, November 20th, 2021!&lt;&#x2F;p&gt;
&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;This was a great experience for me, and @lopopolo&#x27;s stewardship of the project reminded me of both Ruby&#x27;s value of niceness and Rust&#x27;s value of inclusivity. It led directly to a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;artichoke&#x2F;rand_mt&#x2F;pull&#x2F;116&quot;&gt;second PR&lt;&#x2F;a&gt; and I hope to keep contributing in the future to learn more about both Rust and Ruby.&lt;&#x2F;p&gt;
&lt;p&gt;Links:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The Artichoke Ruby project: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;artichoke&#x2F;artichoke&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;artichoke&#x2F;artichoke&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;The Artichoke public Discord server: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;discord.gg&#x2F;QCe2tp2&quot;&gt;https:&#x2F;&#x2F;discord.gg&#x2F;QCe2tp2&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Pipes in Elixir</title>
        <published>2021-11-16T20:53:55+00:00</published>
        <updated>2021-11-16T20:53:55+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2021/11/16/pipes-in-elixir/"/>
        <id>https://briankung.dev/2021/11/16/pipes-in-elixir/</id>
        
        <content type="html" xml:base="https://briankung.dev/2021/11/16/pipes-in-elixir/">&lt;p&gt;Pipes are a delightful feature in Elixir that you can use to pass the evaluation of an expression into a function. For example, the code below will output &quot;Hello, world!&quot; to the terminal:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;Hello, world!&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #179299;&quot;&gt;|&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; IO&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;inspect&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;# &amp;quot;Hello, world!&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can use this to chain together different operations:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;Hello, world!&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #179299;&quot;&gt;|&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; String&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;reverse&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #179299;&quot;&gt;|&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; IO&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;inspect&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;# &amp;quot;!dlrow ,olleH&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And Elixir specifically substitutes the result of the expression into the &lt;em&gt;first&lt;&#x2F;em&gt; argument of the following function, so you can still tack arguments onto the end:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;Hello, world!&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #179299;&quot;&gt;|&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; String&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;reverse&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #179299;&quot;&gt;|&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; String&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;upcase&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #179299;&quot;&gt;|&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; IO&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;inspect&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;label&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;SHOUTING BACKWARDS&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;font-style: italic;&quot;&gt;# SHOUTING BACKWARDS: &amp;quot;!DLROW ,OLLEH&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Pipes can help visually represent the path data takes as it flows through your application. At this point, I&#x27;m probably using them a bit too much, but it&#x27;s just too much fun.&lt;&#x2F;p&gt;
&lt;p&gt;This is cool because in a lot of languages, you can&#x27;t represent how your data is processed in such an orderly fashion because you need to adhere to the order that the programming language understands it - inside out. For example, without pipes, the last example would look like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;IO&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;inspect&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;upcase&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;reverse&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;Hello, world!&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)),&lt;&#x2F;span&gt;&lt;span&gt; label&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;SHOUTING BACKWARDS&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Or, with some indentation to make it somewhat easier on the eyes:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;IO&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;inspect&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;  String&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;upcase&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;    String&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;reverse&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt;&amp;quot;Hello, world!&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;  ),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  label&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #40A02B;&quot;&gt; &amp;quot;SHOUTING BACKWARDS&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Typically, a programming language has &lt;em&gt;functions&lt;&#x2F;em&gt; that operate on certain &lt;em&gt;inputs&lt;&#x2F;em&gt;, but, like mathematical functions, those inputs are entered inside the parentheses. If you remember the form &lt;code&gt;f(x) = x + 1&lt;&#x2F;code&gt; from math class, then you might understand that to solve for &lt;code&gt;g(f(x))&lt;&#x2F;code&gt;, you need to read it backwards in order to evaluate it: first, you must know what &lt;code&gt;x&lt;&#x2F;code&gt; is, then you have to solve &lt;code&gt;f(x)&lt;&#x2F;code&gt; in order to finally solve for &lt;code&gt;g(x)&lt;&#x2F;code&gt;. The way programming languages operate is similar, except that it&#x27;s the computer that&#x27;s doing the solving, or evaluation, of your code. Pipes let you invert that and visually represent it as &quot;first x, then apply f, then g&quot; or &lt;code&gt;x ➡️ f `➡️` g&lt;&#x2F;code&gt;, to use pseudo-code.&lt;&#x2F;p&gt;
&lt;p&gt;Feel free to play with these examples here: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;replit.com&#x2F;@briankung&#x2F;Pipes-in-Elixir&quot;&gt;https:&#x2F;&#x2F;replit.com&#x2F;@briankung&#x2F;Pipes-in-Elixir&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Why Elixir? ⚗️🧪</title>
        <published>2021-11-01T22:55:03+00:00</published>
        <updated>2021-11-01T22:55:03+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2021/11/01/why-elixir/"/>
        <id>https://briankung.dev/2021/11/01/why-elixir/</id>
        
        <content type="html" xml:base="https://briankung.dev/2021/11/01/why-elixir/">&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;elixir-lang.org&#x2F;&quot;&gt;Elixir&lt;&#x2F;a&gt;, other than being an alchemical cure-all, does double duty as a programming language that&#x27;s good for fast, resilient, parallel computing. It has all the syntactical charm of Ruby, with the power of an alien (actually Swedish, but close enough) technology. But why am I learning Elixir now, after so many years of Ruby?&lt;&#x2F;p&gt;
&lt;p&gt;To understand why Elixir is particularly compelling to learn right now, you have to know a bit of the context of computing. For a while, from roughly the 1960s through the early 2000s, there was a golden period of computing hardware advancements in which processing &quot;power&quot; doubled every two years. It was fantastic unless you liked keeping your computer for longer than a year. However, unlike power levels in Dragonball Z, processing power is nuanced.&lt;&#x2F;p&gt;
&lt;p&gt;What everyone thought of as processing &quot;power&quot; was actually the clock rate, or how many operations a processor could do in a second, and the doubling technically referred to the number of transistors in a processor doubling every 18 months, commonly known as &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Moore%27s_law&quot;&gt;Moore&#x27;s Law&lt;&#x2F;a&gt;. But processors weren&#x27;t being used the way we use computers nowadays - with hundreds, or thousands of things going on at the same time. The way some people use a single browser window with hundreds of tabs would be impossible on the hardware of yesterday. But that&#x27;s rarely the only thing you have going on your computer at once - and that&#x27;s what you know of! Our computers are always hard at work under our very noses, and the hardware has to support all that multitasking.&lt;&#x2F;p&gt;
&lt;p&gt;Your computer is like a busy restaurant kitchen. Whatever the customer orders has to show up on time, but there are a thousand other things that have to happen meanwhile. Vegetables need to be chopped, soup stock heated, meat sliced. When things go wrong, a backlog of orders threatens to swamp the kitchen, slowing everything down. There are a few different ways a computer - or a kitchen - can handle workloads.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Sequential Computing&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The kitchen has one cook. Let&#x27;s say they can cook 1 meal per minute. That&#x27;s a fast cook! But since there&#x27;s only one cook, they can only work on one thing at a time. So if you have 60 people waiting on their meals, the last person is going to get their meal in an hour. That&#x27;s no good. They might be a VIP or a restaurant critic.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Concurrent Computing&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The kitchen still has one cook, but the cook is crafty and can juggle multiple things at once. Someone ordered a soup and a taco? No problem, they&#x27;ll start heating the water for the soup, then they&#x27;ll switch over to make the taco. By the time the taco is done, the water is hot and ready to go, so customers can get 1 taco &lt;em&gt;and&lt;&#x2F;em&gt; 1 soup in the time it takes to make just the soup.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Parallel Computing&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Business is booming and even the blindingly fast, crafty cook can&#x27;t keep up, so they hire more cooks - let&#x27;s say 2 (for now). Now they can do twice the amount of work at the same time! And best of all, they can still use concurrent techniques to make efficient use of their time on multiple tasks.&lt;&#x2F;p&gt;
&lt;p&gt;So what people thought of as &quot;performance&quot; doubling was actually just the single cook getting faster and faster. Which is great, but what if you want to watch YouTube while printing something and messaging your buddies? Well, that single cook - in our case, a single processor - is going to get overwhelmed fairly quickly.&lt;&#x2F;p&gt;
&lt;p&gt;So processor manufacturers started adding cooks.&lt;&#x2F;p&gt;
&lt;p&gt;You may have heard of processor cores. They are analogous to the cooks in our metaphor. Whereas processors of yore only had one core, processors now have sometimes over a hundred cores in the same piece of silicon. This abundance of &quot;cooks&quot; lets your processor speed things up in a different way than just running a single task faster. And what&#x27;s more, processor manufacturers effectively &lt;em&gt;stopped being able to manufacture&lt;&#x2F;em&gt; cores that were faster on a pure operations-per-second basis, so they had no other choice if they were to remain competitive - they had hit the limitations of physics in terms of clock rates.&lt;&#x2F;p&gt;
&lt;p&gt;Now, on the software side, many programming languages had only been designed to take advantage of one processor core at a time - sequential computing, basically. While processor cores were doubling in clock speed every 2 years, this wasn&#x27;t much of a problem. If there was a performance problem, programmers could punt it down the line to their future counterparts who would have exponentially faster hardware at their disposal.&lt;&#x2F;p&gt;
&lt;p&gt;But when the last gigahertz marketing campaign died, sequential computing wasn&#x27;t too far behind. There are a lot of clever ways to get around this - &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Asynchrony_(computer_programming)&quot;&gt;asynchrony&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Thread_(computing)&quot;&gt;threads&lt;&#x2F;a&gt;, for example - but it turns out that it is not really something you can tack onto a programming language later. To go back to our analogy, if you have two chefs and they both try to use the ladle at the same time, a fight could break out, or if they both receive an order at same time, one might use up an ingredient before the other gets to it. A properly parallel programming language has to be able to orchestrate all of that at the same time.&lt;&#x2F;p&gt;
&lt;p&gt;Enter &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.erlang.org&#x2F;&quot;&gt;Erlang&lt;&#x2F;a&gt;. Erlang, Elixir&#x27;s parent language, so to speak, was invented from the get-go in 1986 to handle many thousands of concurrent connections because it was born in an environment that required it - telephony, the original social network. To crib a bit from &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Erlang_(programming_language)&quot;&gt;Wikipedia&lt;&#x2F;a&gt;, it specifically needed to be:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Distributed_computing&quot;&gt;Distributed&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Fault_tolerance&quot;&gt;Fault-tolerant&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Soft_real-time&quot;&gt;Soft real-time&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;High_availability&quot;&gt;Highly available&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Uptime&quot;&gt;non-stop&lt;&#x2F;a&gt; applications&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Hot_swapping#Software&quot;&gt;Hot swapping&lt;&#x2F;a&gt;, where code can be changed without stopping a system.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;...in order to comfortably handle and maintain switches between phone users. One particularly important idea in Erlang is that &lt;em&gt;everything is a process&lt;&#x2F;em&gt;. You could &lt;em&gt;almost&lt;&#x2F;em&gt; say that &lt;em&gt;everything gets a single cook&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Elixir inherited all of that from Erlang, and a heavy dose of Ruby sensibilities from its creator, José Valim. Ruby and Elixir are both elegant programming languages for different reasons, but Elixir&#x27;s inheritance means that it&#x27;s better suited for parallel computing workloads that are becoming more and more important as hardware diversifies past the gigahertz wars.&lt;&#x2F;p&gt;
&lt;p&gt;Elixir provides particularly compelling bait for web developers who are looking to provide near real-time user experiences while scaling up to possibly millions of users at the same time.&lt;&#x2F;p&gt;
&lt;p&gt;If you&#x27;re interested in learning Elixir, you can start at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;elixir-lang.org&#x2F;&quot;&gt;https:&#x2F;&#x2F;elixir-lang.org&#x2F;&lt;&#x2F;a&gt;. I can personally recommend Dave Thomas&#x27;s book, &lt;em&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pragprog.com&#x2F;titles&#x2F;elixir16&#x2F;programming-elixir-1-6&#x2F;&quot;&gt;Programming Elixir 1.6&lt;&#x2F;a&gt;&lt;&#x2F;em&gt; for its wonderful exercises and clear, but concise writing style (if you&#x27;re in the business of buying programming books, you can also save yourself a lot of time and money by getting your books through an ACM membership). You can also find Elixir on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;elixir-slackin.herokuapp.com&#x2F;&quot;&gt;Slack&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;discord.gg&#x2F;elixir&quot;&gt;Discord&lt;&#x2F;a&gt;. Otherwise, I&#x27;m just starting on my Elixir journey, so feel free to geek out about it with me &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.twitter.com&#x2F;briankung&quot;&gt;@briankung&lt;&#x2F;a&gt; on Twitter!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Trying Elixir as a Rubyist</title>
        <published>2021-10-31T21:43:38+00:00</published>
        <updated>2021-10-31T21:43:38+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2021/10/31/trying-elixir-as-a-rubyist/"/>
        <id>https://briankung.dev/2021/10/31/trying-elixir-as-a-rubyist/</id>
        
        <content type="html" xml:base="https://briankung.dev/2021/10/31/trying-elixir-as-a-rubyist/">&lt;figure&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;assets&#x2F;images&#x2F;trip-hazard-g42f62b8c1_640-e1635785693452.png&quot;&gt;&lt;img src=&quot;&#x2F;assets&#x2F;images&#x2F;trip-hazard-g42f62b8c1_640-e1635785693452.png&quot; alt=&quot;Warning sign of stick figure tripping over something&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;figcaption&gt;
&lt;p&gt;Elixir is similar enough to Ruby to be familiar, but different enough to get tripped up by! &lt;em&gt;Image by &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pixabay.com&#x2F;users&#x2F;openicons-28911&#x2F;?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=98658&quot;&gt;OpenIcons&lt;&#x2F;a&gt; from &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pixabay.com&#x2F;?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=98658&quot;&gt;Pixabay&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;I&#x27;ve been working through Dave Thomas&#x27;s fantastic book &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pragprog.com&#x2F;titles&#x2F;elixir16&#x2F;programming-elixir-1-6&#x2F;&quot;&gt;Programming Elixir 1.6&lt;&#x2F;a&gt; in hopes of using Phoenix LiveView, and it has been really interesting, coming from Ruby. A lot of syntax is familiar enough to be alluring, but unfamiliar enough to trip me up. For instance, even something as simple as an &lt;code&gt;if&lt;&#x2F;code&gt; block was hard to write fluently:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D20F39;&quot;&gt; true&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  something&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  something_else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Rubyists, did you catch it? &lt;code&gt;if&lt;&#x2F;code&gt; statements in Elixir have a &lt;em&gt;mandatory&lt;&#x2F;em&gt; &lt;code&gt;do...end&lt;&#x2F;code&gt; block. I got stuck for longer than I’d like to admit trying to compile my Elixir code only to have it complain about superfluous &lt;code&gt;end&lt;&#x2F;code&gt; keywords.&lt;&#x2F;p&gt;
&lt;p&gt;As it turns out, this makes sense because &lt;code&gt;do...end&lt;&#x2F;code&gt; blocks are syntactic sugar for appending a keyword list to a function, and &lt;code&gt;if&lt;&#x2F;code&gt; is just a function in Elixir. But in Ruby, &lt;code&gt;do...end&lt;&#x2F;code&gt; blocks in &lt;code&gt;if&lt;&#x2F;code&gt; statements are not even valid (that I know of).&lt;&#x2F;p&gt;
&lt;p&gt;I encountered a similar syntactical hiccup when converting short form function definitions to long ones in Elixir. Short function definitions follow this syntax:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;def&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; somefunc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;arg&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;),&lt;&#x2F;span&gt;&lt;span&gt; do:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt; IO&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;inspect&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;arg&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;…while long function definitions look like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #4C4F69; background-color: #EFF1F5;&quot;&gt;&lt;code data-lang=&quot;elixir&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;def&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt; somefunc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;arg&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DF8E1D;font-style: italic;&quot;&gt;  IO&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #1E66F5;font-style: italic;&quot;&gt;inspect&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;arg&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7C7F93;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8839EF;&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Again, the differences are slight, but incompatible - and again, they make sense when you realize what the &lt;code&gt;do...end&lt;&#x2F;code&gt; syntactic sugar is for. The short form of function definition requires a comma after the function arguments, and the long form will throw a syntax error if you forget to delete the comma and simply move the function body into a &lt;code&gt;do...end&lt;&#x2F;code&gt; block. This is, as before, because the &lt;code&gt;do...end&lt;&#x2F;code&gt; block is simply sugar for &lt;code&gt;do: (function_body)&lt;&#x2F;code&gt; keyword list. But in order for it to be parsed as a keyword list in the short function definition, it needs the comma.&lt;&#x2F;p&gt;
&lt;p&gt;Once again, it makes sense! But it’s a tripping hazard for Rubyists.&lt;&#x2F;p&gt;
&lt;p&gt;Ironically, I couldn’t remember if the &lt;code&gt;do:&lt;&#x2F;code&gt; keyword list in the short function definition required the &lt;code&gt;end&lt;&#x2F;code&gt; keyword - even when writing this post! Spoiler: it is a syntax error.&lt;&#x2F;p&gt;
&lt;p&gt;It’s also a bit of a paradigm shift to write in a fully functional language after writing object oriented, message-passing Ruby code for so long, but I’ll leave that for another post.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Hello, World!</title>
        <published>2021-10-31T12:07:06+00:00</published>
        <updated>2021-10-31T12:07:06+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://briankung.dev/2021/10/31/hello-world-2/"/>
        <id>https://briankung.dev/2021/10/31/hello-world-2/</id>
        
        <content type="html" xml:base="https://briankung.dev/2021/10/31/hello-world-2/">&lt;p&gt;My homepage looks so lonely without a post that I thought I&#x27;d write something really quickly. It&#x27;s been a long time since I wrote in a blog.&lt;&#x2F;p&gt;
&lt;p&gt;I hope to jot down thoughts about a few of the things I&#x27;ve been working on lately here, including, but not limited to:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Rust&lt;&#x2F;li&gt;
&lt;li&gt;Elixir &#x2F; Phoenix&lt;&#x2F;li&gt;
&lt;li&gt;OS development (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;os.phil-opp.com&#x2F;&quot;&gt;https:&#x2F;&#x2F;os.phil-opp.com&#x2F;&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Ruby as I discover new, weird corners of it&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;No doubt some hints of my humanity will leak out as well - the tagline is ⅔ non-programming, after all.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
