<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.8.3">Jekyll</generator><link href="blog.systems.ethz.ch/feed.xml" rel="self" type="application/atom+xml" /><link href="blog.systems.ethz.ch/" rel="alternate" type="text/html" /><updated>2022-04-21T08:03:48+00:00</updated><id>blog.systems.ethz.ch/</id><entry><title type="html">RumbleML, a declarative machine learning framework</title><link href="blog.systems.ethz.ch/blog/2020/rumbleML.html" rel="alternate" type="text/html" title="RumbleML, a declarative machine learning framework" /><published>2020-06-17T00:00:00+00:00</published><updated>2020-06-17T00:00:00+00:00</updated><id>blog.systems.ethz.ch/blog/2020/rumbleML</id><content type="html" xml:base="blog.systems.ethz.ch/blog/2020/rumbleML.html">&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;/h1&gt;

&lt;p&gt;Machine learning is an essential cornerstone of contemporary computer science. Its influence spans across various industries while tackling a widening range of complex problems which require increasingly sophisticated solutions. This field’s immense popularity reflects an increasing number of machine learning engineers and data scientists joining the ranks.&lt;/p&gt;

&lt;p&gt;Unfortunately, throwing more resources at a problem is rarely the optimal solution. Specifically, we cannot simply rely on having bigger teams of engineers to solve complex problems. Instead, better tooling and improved methodologies can drive machine learning forward in a much more reliable and feasible manner. To this end, I will introduce the RumbleML machine learning framework in this article.&lt;/p&gt;

&lt;p&gt;RumbleML is designed to address the two main problems with present-day machine learning tools that hinder productivity:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Poor data independence due to the imperative nature&lt;/li&gt;
  &lt;li&gt;Limited out of the box scalability and distributed processing support.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;data-independence&quot;&gt;Data Independence&lt;/h1&gt;

&lt;p&gt;Wikipedia, the holy grail of internet knowledge, contains one of the best definitions I came across on data independence:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“[Data independence] refers to the immunity of user applications to changes made in the definition and organization of data.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In other words, users can focus solely on their application semantics while they can rely on the system to handle underlying data operation complexity. The definition continues as follows:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“Application programs should not, ideally, be exposed to details of data representation and storage.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This layering is best achieved by resorting to declarative paradigms. A declarative language is a language in which the users specify what they want rather than specifying how they want it. Properly achieved declarative nature brings good abstractions which render the system much easier to use. This, in turn, enables the users to be more productive and write comparably more bug-free code.&lt;/p&gt;

&lt;p&gt;The trend of resorting the declarative paradigms instead of imperative ones has been continually gaining traction with modern languages and frameworks. For example, multi-paradigm languages such as Scala and JavaScript are becoming increasingly prominent. Additionally, the web technologies that enable you to display this article on your browser are also fueled by the underlying declarative nature of HTML and potentially by the declarative web frameworks such as “React.js”. Yet, when we look at the domain of machine learning, most frameworks expose APIs in imperative languages. This leads to limited productivity as users are encumbered to handle algorithm semantics, underlying data representations, and runtime execution all at once. Therefore, switching to declarative paradigms for machine learning frameworks could go a long way in enhancing user productivity.&lt;/p&gt;

&lt;h1 id=&quot;scalability&quot;&gt;Scalability&lt;/h1&gt;

&lt;p&gt;Another shortcoming of popular ML frameworks is the reliance on additional tools to provide scalability. The need for additional tools increases the burden on the users as they are forced to handle a larger tech stack during development and maintenance. Said additional tools also commonly expose iterative APIs that further aggravate the data independence limitations. For example, Apache Spark is a fantastic framework that provides scalability via distributed processing. It provides out of the box distributed scalability for arbitrary user programs. In other words, custom machine learning algorithms can be made scalable by using Spark. However, this can easily turn into a daunting task as Spark offers APIs only in imperative languages which require substantial effort to implement algorithm semantics.&lt;/p&gt;

&lt;p&gt;The SparkML library, which is built into the Spark framework, offers a large variety of already implemented machine learning algorithms. If the desired use case fits into one of these available algorithms, the implementation efforts can be immensely minimized. Furthermore, If the data is already structured, applying machine learning would be almost trivial.&lt;/p&gt;

&lt;p&gt;Unfortunately, in real-world applications, data is hardly ever in a state that is ripe for applying machine learning. Data cleaning and pre-processing operations are vital to the majority of machine learning pipelines. This is where the lack of data independence due to imperative APIs becomes a real pain point for the users. In the presence of unstructured data, which can be heterogeneous and nested, the best solution that Spark can offer is casting everything down to strings. This is extremely far from ideal as the entire type information gets lost in the process and the user is offered little to no help by the system in picking up the pieces.&lt;/p&gt;

&lt;h1 id=&quot;enter-rumble&quot;&gt;Enter Rumble&lt;/h1&gt;

&lt;p&gt;The Rumble engine is introduced to address shortcomings of Spark with regards to heterogeneous data and the lack of data independence. Rumble interfaces Spark with functional and declarative querying language “JSONiq”. JSONiq inherits %95 of its features from XQuery while leaving out the peculiar and hard to understand bits. JSONiq language is fully composable and Turing-complete. The Rumble engine automatically maps the user queries written in JSONiq to Spark runtime execution plans. This enables users to have the scalability of Spark at no additional implementation cost while having full support for heterogeneous data processing.&lt;/p&gt;

&lt;div class=&quot;image&quot;&gt;
    &lt;img src=&quot;/assets/posts/2020-06-17-rumbleML/Img1-Rumble.png&quot; width=&quot;100%&quot; /&gt;
    &lt;span&gt;Fig1. Spark + JSONiq = Rumble&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;The most prominent feature of JSONiq is the FLWOR expression as it provides the expressiveness of SQL’s SELECT-FROM-WHERE statements in the context of heterogeneous data. The querying and data manipulation capabilities of FLWOR expression will be briefly demonstrated with a simplified example. (The original example is taken from an earlier blogpost on Rumble which can be found in references). Imagine we have the following “person” data set that contains name and year data where year is both heterogeneous and nested.&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Peter&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Year&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2015&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2014&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;John&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Year&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2013&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2018&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;	&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;heterogeneous&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Helen&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Year&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2012&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2017&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2019&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;	&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;nested&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The following query aggregates the year data as JSONiq’s FLWOR expression immensely simplifies the processing of this heterogeneous dataset. Performing the same task with a non-declarative and non-heterogeneity supporting language immediately turns into low-level programming as the user is forced to handle the iteration and type information manually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Query:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$person&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;people.json&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$years&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flatten&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;$person&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Year&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Name&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$person&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;NumberOfYears&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;$years&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Peter&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;NumberOfYears&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;John&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;NumberOfYears&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Helen&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;NumberOfYears&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;standing-on-the-shoulders-of-giants-rumbleml&quot;&gt;Standing on the Shoulders of Giants: RumbleML&lt;/h1&gt;

&lt;p&gt;The Rumble engine recently took its capabilities yet another big step further. SparkML, that was mentioned earlier, is quite extensive as it is backed by a strong open source community of academics and professionals. Since Rumble was already capable of interfacing Spark, the engine was extended further to interface the capabilities of the SparkML library as well. Through these efforts, the RumbleML framework was conceived. This enabled the existing user productivity and automatic optimization benefits of Rumble to be complemented with ready to use algorithms of RumbleML. With its initial release, RumbleML has achieved over 80% coverage of the functionality offered by SparkML. The development efforts for increasing coverage and optimizing performance further are currently ongoing.&lt;/p&gt;

&lt;div class=&quot;image&quot;&gt;
    &lt;img src=&quot;/assets/posts/2020-06-17-rumbleML/Img2-RumbleML.png&quot; width=&quot;100%&quot; /&gt;
    &lt;span&gt;Fig2. Rumble + ML = RumbleML&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;At a high level, a machine learning query on Rumble can be imagined to consist of three main steps which are common across many similar frameworks: data loading, model training, model usage (omitting the evaluation steps). An example pipeline of this nature is demonstrated in pseudo-code format below:&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$train_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(...)&lt;/span&gt;       &lt;span class=&quot;c1&quot;&gt;// structured data ready to be used in ML&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$test_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(...)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;train&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;$train_data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// model training is a higher order function that returns a model function &lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;$test_data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;               &lt;span class=&quot;c1&quot;&gt;// apply the model function to get predictions&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The concrete implementation and usage of RumbleML revolve around mapping the SparkML concepts to Rumble. The core SparkML concepts of “estimator” and “transformer” are seamlessly mapped into function items of the JSONiq data model. Training sets, test sets, and validation sets, which contain features and labels, are exposed through JSONiq sequences of object items: the keys of these objects are the features and labels. As such, RumbleML simply delegates computation to SparkML without re-inventing the wheel.&lt;/p&gt;

&lt;h1 id=&quot;transformers&quot;&gt;Transformers&lt;/h1&gt;

&lt;p&gt;A transformer is a function item that maps a sequence of objects to a sequence of objects. It is an abstraction that either performs a feature transformation or generates predictions based on trained models. For example:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Tokenizer is a feature transformer that receives textual input data and splits it into individual terms (usually words), which are called tokens.&lt;/li&gt;
  &lt;li&gt;KMeansModel is a trained model and a transformer that can read a dataset containing features and generate predictions as its output.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tokenizer operation:&lt;/p&gt;

&lt;div class=&quot;image&quot;&gt;
    &lt;img src=&quot;/assets/posts/2020-06-17-rumbleML/Img3-TokenizerExample.png&quot; width=&quot;100%&quot; /&gt;
    &lt;span&gt;Fig3. Tokenizer operation&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;KMeans operation:&lt;/p&gt;

&lt;div class=&quot;image&quot;&gt;
    &lt;img src=&quot;/assets/posts/2020-06-17-rumbleML/Img4-KMeansExample.png&quot; width=&quot;100%&quot; /&gt;
    &lt;span&gt;Fig4. KMeans operation&lt;/span&gt;
&lt;/div&gt;

&lt;h1 id=&quot;estimators&quot;&gt;Estimators&lt;/h1&gt;

&lt;p&gt;An estimator is a function item that maps a sequence of objects to a transformer. Since it is a function that returns another function, an estimator is a “higher-order function”. Estimators abstract the concept of a machine learning algorithm that fits or trains on data. For example, a learning algorithm such as KMeans is implemented as an Estimator. Calling this estimator on data essentially trains a KMeansModel, which is a Model and hence a Transformer.&lt;/p&gt;

&lt;p&gt;Now having these concrete concepts in place, the previous query can be written in the format that can be directly executed in Rumble.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$train_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;structured&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/path/to/training/data&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$test_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;structured&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/path/to/test/data&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$estimator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;estimator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;KMeans&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$estimator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;$train_data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;k&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;})&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;// Train KMeans with k=2&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;$test_data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;                           &lt;span class=&quot;c1&quot;&gt;// apply model&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now putting it all together, RumbleML provides out of the box machine learning algorithm support. Rumble on the other hand offers fully composable querying capabilities of JSONiq to handle pre-processing of semi-structured data.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$raw_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;people.json&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$preprocessed_train_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$person&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$raw_data&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$years&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flatten&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;$person&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Year&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Name&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$person&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;NumberOfYears&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;$years&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$preprocessed_train_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;annotate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;$preprocessed_train_data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Name&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;string&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;NumberOfYears&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;integer&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$estimator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;estimator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;KMeans&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$estimator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;$preprocessed_train_data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;k&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;})&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;// Train KMeans with k=2&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$test_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;structured&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;people_test.json&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;$test_data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;To wrap up, RumbleML is a new machine learning framework that aims to provide superior usability and scalability benefits compared to alternative ML frameworks thanks to its declarative nature and utilization of Apache Spark.&lt;/p&gt;

&lt;h1 id=&quot;why-should-you-try-rumble--rumbleml&quot;&gt;Why should you try Rumble &amp;amp; RumbleML?&lt;/h1&gt;

&lt;p&gt;I would strongly recommend trying Rumble for yourself by following the simple steps in our get-started page if any of the following apply to you:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Working with semi-structured, heterogeneous (mixed types) &amp;amp; nested data (JSON, CSV, Text, Parquet, Avro, and more…)&lt;/li&gt;
  &lt;li&gt;Working with machine learning whether you are a beginner or an expert (More than 70 featurization operations and ML algorithms are available out of the box)&lt;/li&gt;
  &lt;li&gt;Require scaling capabilities that range into terabytes (whether standalone Spark or on a cluster)&lt;/li&gt;
  &lt;li&gt;Curious about big data&lt;/li&gt;
  &lt;li&gt;Love open-source technologies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have any recommendations or run into any trouble, please feel free to create an issue at our open-source repository on GitHub.&lt;/p&gt;

&lt;h1 id=&quot;references&quot;&gt;References&lt;/h1&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/RumbleDB/rumble/&quot;&gt;https://github.com/RumbleDB/rumble/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://rumble.readthedocs.io/en/latest/Getting%20started/&quot;&gt;https://rumble.readthedocs.io/en/latest/Getting%20started/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Rumble, an engine to run JSONiq on top of Spark, G. Fourny – Blogpost, &lt;a href=&quot;https://blog.systems.ethz.ch/blog/2019/rumble.html&quot;&gt;https://blog.systems.ethz.ch/blog/2019/rumble.html&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;SystemML: Declarative Machine Learning on Spark, M. Boehm et. al., Proceedings of the VLDB Endowment, Volume 9, 2015-2016, &lt;a href=&quot;http://www.vldb.org/pvldb/vol9/p1425-boehm.pdf&quot;&gt;http://www.vldb.org/pvldb/vol9/p1425-boehm.pdf&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><author><name>Can Berker Cikis</name></author><summary type="html">This piece introduces the need for and the benefits of RumbleML framework. Particularly, this framework addresses the shortcomings of contemporary ML frameworks of iterative nature by utilizing declarative paradigms instead.</summary></entry><entry><title type="html">Building an inverted index on a large text collection with JSONiq</title><link href="blog.systems.ethz.ch/blog/2019/standard-inverted-index-with-JSONiq.html" rel="alternate" type="text/html" title="Building an inverted index on a large text collection with JSONiq" /><published>2019-08-21T00:00:00+00:00</published><updated>2019-08-21T00:00:00+00:00</updated><id>blog.systems.ethz.ch/blog/2019/standard-inverted-index-with-JSONiq</id><content type="html" xml:base="blog.systems.ethz.ch/blog/2019/standard-inverted-index-with-JSONiq.html">&lt;p&gt;One of the textbook examples for parallel processing is building a standard inverted index in the context of information retrieval. In this post, we will show how &lt;a href=&quot;http://rumbledb.org&quot;&gt;Rumble&lt;/a&gt;, a &lt;a href=&quot;http://www.jsoniq.org&quot;&gt;JSONiq&lt;/a&gt; engine running on Spark, can be used to build such an index in only a few lines of code. This demonstrates that, even if the input is not JSON but a collection of strings (lines of text), JSONiq can handle it and easily create an index in the JSON format.&lt;/p&gt;

&lt;h1 id=&quot;the-corpus&quot;&gt;The Corpus&lt;/h1&gt;

&lt;p&gt;For the purpose of this post, we will use the complete text of Sherlock Holmes books, which can be found and downloaded &lt;a href=&quot;https://sherlock-holm.es/ascii/&quot;&gt;here&lt;/a&gt;. The code, however, can be used with any input collection.&lt;/p&gt;

&lt;p&gt;There is nothing particular about this file; it is just text organized in a large number of small lines:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;



                          THE COMPLETE SHERLOCK HOLMES

                               Arthur Conan Doyle



                                Table of contents

               A Study In Scarlet

               The Sign of the Four

                  The Adventures of Sherlock Holmes
               A Scandal in Bohemia
               The Red-Headed League
               A Case of Identity
               The Boscombe Valley Mystery
               The Five Orange Pips
               The Man with the Twisted Lip
               The Adventure of the Blue Carbuncle
               The Adventure of the Speckled Band
               The Adventure of the Engineer's Thumb
               The Adventure of the Noble Bachelor
               The Adventure of the Beryl Coronet
               The Adventure of the Copper Beeches
...               
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In general, the approach described here will also work with a large number of files. Spark can partition the lines across but also within one file.&lt;/p&gt;

&lt;h1 id=&quot;reading-a-large-collection-of-strings&quot;&gt;Reading a large collection of strings&lt;/h1&gt;

&lt;p&gt;Rumble introduces the &lt;code class=&quot;highlighter-rouge&quot;&gt;json-file() &lt;/code&gt; function to read any number of JSON Lines files as a sequence of objects.&lt;/p&gt;

&lt;p&gt;However, the data model of JSONiq supports sequences of any items – the function &lt;code class=&quot;highlighter-rouge&quot;&gt;text-file()&lt;/code&gt; reads any number of text files and returns a sequence of strings: one for each line.&lt;/p&gt;

&lt;p&gt;Internally, Rumble actually manipulates a Spark RDD of string items.&lt;/p&gt;

&lt;p&gt;An idempotent query that returns the entire collection would be&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;text-file(&quot;sherlock.txt&quot;, 100)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Where we use 100 partitions. Or more generally to read an entire directory:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;text-file(&quot;/home/ghislain/corpus/*&quot;, 100)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The following query is equivalent but explicitly binds each line to a variable:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;for $line in text-file(&quot;sherlock.txt&quot;, 100)
return $lin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The above queries (assuming they lie in the file query.jq) can be run on the CLI locally with:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;spark-submit spark-rumble-1.1.jar \
    --query-path ./query.jq \
    --output-path ./output-directory
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;as well as on a cluster by submitting the appropriate parameters to spark-submit.&lt;/p&gt;

&lt;p&gt;Omitting –output-path on a local execution will simply print on the standard input – it can be the best for experimenting. Only the top 1000 items will be shown to avoid a crash, but this can be changed with –result-size.&lt;/p&gt;

&lt;p&gt;The output of all queries above will be in the typical format after a MapReduce of Spark job: a directory filled with part-iiiii files.&lt;/p&gt;

&lt;p&gt;This is what we will start with.&lt;/p&gt;

&lt;h1 id=&quot;tokenizing&quot;&gt;Tokenizing&lt;/h1&gt;

&lt;p&gt;The next step in building a standard inverted index is to tokenize the lines. Tokenization in information retrieval is in itself a core topic: it may involve lemmatization, stemming, etc. Here, we will keep it simple. Let us try as a start to simply tokenize based on spaces.&lt;/p&gt;

&lt;p&gt;In order to do so, we just need to add a second for loop on an invocation of the tokenize() function, which returns a sequence of strings:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;for $line in text-file(&quot;sherlock.txt&quot;, 100)
for $token in tokenize($line, &quot; &quot;)
where $token ne &quot;&quot;
return $token
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We added the where clause to filter out any empty strings (when a line starts with a space, for example):&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;THE
COMPLETE
SHERLOCK
HOLMES
Arthur
Conan
Doyle
Table
of
contents
A
Study
In
Scarlet
The
Sign
of
the
Four
The
Adventures
of
Sherlock
Holmes
A
Scandal
in
Bohemia
The
Red-Headed
League
A
Case
of
Identity
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;getting-the-distinct-terms&quot;&gt;Getting the distinct terms&lt;/h1&gt;

&lt;p&gt;There are of course duplicates; we could eliminate them with a distinct-values call (this will be executed in parallel as well):&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;distinct-values(
  for $line in text-file(&quot;sherlock.txt&quot;, 100)
  for $token in tokenize($line, &quot; &quot;)
  where $token ne &quot;&quot;
  return $token
)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;However, since we want to associate each unique term with a postings list, a group-by is a better idea. The order clause will also sort them alphabetically, like so:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;for $line in text-file(&quot;sherlock.txt&quot;, 100)
for $token in tokenize($line, &quot; &quot;)
where $token ne &quot;&quot;
group by $token
order by $token ascending  
return $token
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Since we didn’t do any cleanup, we get a lot of special characters.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;
&quot;'&quot;A
&quot;'&quot;Ah,
&quot;'&quot;And
&quot;'&quot;But
&quot;'&quot;Done!&quot;
&quot;'&quot;Gone!
&quot;'&quot;Ha,
&quot;'&quot;He
&quot;'&quot;Hullo,
&quot;'&quot;I
&quot;'&quot;I'd
&quot;'&quot;I'll
&quot;'&quot;I'm
&quot;'&quot;I've
&quot;'&quot;It's
&quot;'&quot;Just
&quot;'&quot;Mr.
&quot;'&quot;No.&quot;
&quot;'&quot;Oh,
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But we can easily adapt the tokenize() function call to get rid of the most common special characters:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;for $line in text-file(&quot;sherlock.txt&quot;, 100)
for $token in tokenize($line, &quot;[ \&quot;'()&amp;amp;!\\-*,:\\.;/]&quot;)
where $token ne &quot;&quot;
group by $token
order by $token ascending
return $token
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Which now looks better: numbers first.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;000
1
10
100
1000
104
109
10s
10th
11
117
117th
11th
12
126b
127
129
12s
12th
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;postings-lists&quot;&gt;Postings lists&lt;/h1&gt;

&lt;p&gt;The next step is to build the postings lists (we will here assume we have a posting for each term appearing in a line). We need to assign each line to a doc-id.&lt;/p&gt;

&lt;p&gt;This can be done with the count clause. Also, in the return clause, we now need to return a more structured construct with a nested array of doc-ids. The syntax is that of JSON, but with the possibility to dymamically compute values with nested JSONiq expressions.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;for $line in text-file(&quot;sherlock.txt&quot;, 100)
count $docid
for $token in tokenize($line, &quot;[ \&quot;'()&amp;amp;!\\-*,:\\.;/]&quot;)
where $token ne &quot;&quot;
group by $token
order by $token ascending
return {
  &quot;Term&quot; : $token,
  &quot;Postings&quot; : [ distinct-values( $docid ) ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Et voilà :&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{ &quot;Term&quot; : &quot;000&quot;, &quot;Postings&quot; : [ 11552, 11631, 11634, 13921, 19725 ] }
{ &quot;Term&quot; : &quot;1&quot;, &quot;Postings&quot; : [ 615, 3497, 3582, 9657, 22687, 33863, 40408, 62344, 76758 ] }
{ &quot;Term&quot; : &quot;10&quot;, &quot;Postings&quot; : [ 629, 13928, 27179, 46790, 69917, 76367 ] }
{ &quot;Term&quot; : &quot;100&quot;, &quot;Postings&quot; : [ 66036 ] }
{ &quot;Term&quot; : &quot;1000&quot;, &quot;Postings&quot; : [ 20669, 22683 ] }
{ &quot;Term&quot; : &quot;104&quot;, &quot;Postings&quot; : [ 67353 ] }
{ &quot;Term&quot; : &quot;109&quot;, &quot;Postings&quot; : [ 51994 ] }
{ &quot;Term&quot; : &quot;10s&quot;, &quot;Postings&quot; : [ 14806, 17882 ] }
{ &quot;Term&quot; : &quot;10th&quot;, &quot;Postings&quot; : [ 14104 ] }
{ &quot;Term&quot; : &quot;11&quot;, &quot;Postings&quot; : [ 630, 2129, 12617, 18052, 17974, 21106, 27179, 62403, 64203 ] }
{ &quot;Term&quot; : &quot;117&quot;, &quot;Postings&quot; : [ 16194, 16199 ] }
{ &quot;Term&quot; : &quot;117th&quot;, &quot;Postings&quot; : [ 27249, 27691 ] }
{ &quot;Term&quot; : &quot;11th&quot;, &quot;Postings&quot; : [ 73290 ] }
{ &quot;Term&quot; : &quot;12&quot;, &quot;Postings&quot; : [ 631, 35064 ] }
{ &quot;Term&quot; : &quot;126b&quot;, &quot;Postings&quot; : [ 24033, 24088, 24075 ] }
{ &quot;Term&quot; : &quot;127&quot;, &quot;Postings&quot; : [ 51993 ] }
{ &quot;Term&quot; : &quot;129&quot;, &quot;Postings&quot; : [ 2088 ] }
{ &quot;Term&quot; : &quot;12s&quot;, &quot;Postings&quot; : [ 16207 ] }
{ &quot;Term&quot; : &quot;12th&quot;, &quot;Postings&quot; : [ 14105 ] }
{ &quot;Term&quot; : &quot;13&quot;, &quot;Postings&quot; : [ 1828, 1887, 1898, 35202, 51993, 62841, 62843, 62921, 63570, 64750, 69239 ] }
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is it. If we output this result to a specific path, say, an “index” folder, we have built our index in the JSON Lines format.&lt;/p&gt;

&lt;h1 id=&quot;querying-the-index&quot;&gt;Querying the index&lt;/h1&gt;

&lt;p&gt;Now we can use JSONiq to query the index. For example, if we want to query for “Crow”, we look up the postings list and scan the document for the lines given by these postings.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;let $postings := json-file(&quot;/tmp/index&quot;)[$$.Term eq &quot;Crow&quot;].Postings[]
for $document in text-file(&quot;sherlock.txt&quot;)
count $line
where $line = $postings
return $document
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And here we go:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;     to the Crow Hill, a huge business which was in strong hands which had
     not only over the killing of the manager and engineer of the Crow
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It should absolutely clear to the reader that, of course, best performance would be achieved with additional data structures such as a B+-tree or hash table to organize terms as well as a direct access to any line of text by its number: scanning at query time defeats the purpose of having an index in the first place.&lt;/p&gt;

&lt;p&gt;However, building a standard inverted index almost gives a textbook example of how to use JSONiq, because it involves many of the different FLWOR clauses as well as a mix between a textual model and a semi-structured model.&lt;/p&gt;

&lt;h1 id=&quot;jsoniq-and-data-independence&quot;&gt;JSONiq and data independence&lt;/h1&gt;

&lt;p&gt;We hope this post showed how JSONiq makes it simpler to do this kind of task than using PySpark or DataFrames. The key feature of the Rumble project is to maintain data independence and have the developer only thing in terms of one thing: sequences of items, even if the data is heterogeneous and/or nested.&lt;/p&gt;</content><author><name>Ghislain  Fourny</name></author><summary type="html">We show how JSONiq can be used not only to manipulate JSON input, but also to build a standard inverted index on and query a text collection.</summary></entry><entry><title type="html">Rumble, an engine to run JSONiq on top of Spark</title><link href="blog.systems.ethz.ch/blog/2019/rumble.html" rel="alternate" type="text/html" title="Rumble, an engine to run JSONiq on top of Spark" /><published>2019-06-06T00:00:00+00:00</published><updated>2019-06-06T00:00:00+00:00</updated><id>blog.systems.ethz.ch/blog/2019/rumble</id><content type="html" xml:base="blog.systems.ethz.ch/blog/2019/rumble.html">&lt;p&gt;The increasing amount of data available to process, as well as the ever-growing discrepancy
between storage capacity, throughput and latency, has forced the database community to come
up with new querying paradigms in the last two decades.&lt;/p&gt;

&lt;p&gt;MapReduce has become very popular due
to its very simple yet general abstraction, which consists in processing key-value pairs in
two phases, mapping and reducing, separated by a shuffling phase. Apache Spark has more recently
generalized the MapReduce paradigm from two phases to a full DAGs of phases called RDDs.&lt;/p&gt;

&lt;p&gt;Yet, this is not the end of the road: MapReduce and Apache Spark are tools, not goals. Writing
a program to query data with Spark in Java, Python or Scala feels more like writing assembly instructions
(the Spark transformations) than high-level code.&lt;/p&gt;

&lt;h1 id=&quot;data-independence&quot;&gt;Data independence&lt;/h1&gt;

&lt;p&gt;A truly data-independent system, in the sense envisioned by Edgar Codd in 1970, must expose
the data to the technical user via a functional, declarative query language accompanied by
a clean data model. Such languages can then be executed on top of MapReduce or Spark in a
way transparent to the user, that is, hiding underlying key-value pairs or RDDs.&lt;/p&gt;

&lt;p&gt;A declarative language is a language in which the user says what they want, not how they want. Rather than
giving a set of instructions, like a cooking recipe (break the eggs, put the sugar, heat up the oven, etc),
the user states what they want (“Mom, can I have a lemon cake?”).&lt;/p&gt;

&lt;p&gt;A functional language is a language in which one manipulates mathematical objects. A program is made
of an arrangement of expressions that take and return these objects, most often deterministically.&lt;/p&gt;

&lt;p&gt;A functional and declarative language leaves
room for interpretation and optimization to the engine: it is then open whether the query runs locally, whether
it is spread across cores, or across machines in a cluster, or whether (who knows) it runs on DNA. A
query optimizer can also rewrite inefficient code, cache intermediate values when it makes sense, etc.&lt;/p&gt;

&lt;h1 id=&quot;is-the-spark-api-functional&quot;&gt;Is the Spark API functional?&lt;/h1&gt;

&lt;p&gt;Some argue the Spark API, whether in Java, Scala or Python, is already declarative and functional. It is
true to some extent, in the sense that transformations are functions that manipulate RDDs. However, there
are a few differences with functional languages in the classical sense:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;From a productivity perspective, the functions are explicitly called, in other words the program is full of parentheses.
A functional language (think Haskell, SQL, …)
typically hides the underlying functions in a natural, easy-to-use, English-like syntax.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;From a performance perspective, the transformations used &lt;em&gt;are&lt;/em&gt; the query plan. Spark will not further optimize and execute
the plan as given by the user.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The manipulated instances (RDD) cohabit with the host language (Java objects, etc). This adds extra complexity to the programming
experience.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;enter-data-frames&quot;&gt;Enter data frames&lt;/h1&gt;

&lt;p&gt;DataFrames were a major improvement in Spark. When RDDs are highly structured (think rows with the same attributes and types),
the underlying memory layout can be optimized, and Spark SQL can be used insted of explicit transformations. This is making
Apache Spark more data independent, with a direct benefit in performance: SQL is declarative and (to some extent) functional, so
that the underlying engine is free to find an optimal query plan, relying on decades of research done in the area of relational
databases.&lt;/p&gt;

&lt;p&gt;For example, if we have an input dataset that looks like so:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{ &quot;Name&quot; : &quot;Peter&quot;, &quot;Year&quot; : 2015 }
{ &quot;Name&quot; : &quot;John&quot;, &quot;Year&quot; : 2018 }
{ &quot;Name&quot; : &quot;Helen&quot;, &quot;Year&quot; : 2016 }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It can be imported into dataframes like so:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Name (string)&lt;/th&gt;
      &lt;th&gt;Year (integer)&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Peter&lt;/td&gt;
      &lt;td&gt;2015&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;John&lt;/td&gt;
      &lt;td&gt;2018&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Helen&lt;/td&gt;
      &lt;td&gt;2016&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;And queried like so:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;SELECT year, COUNT(Name) as count
FROM input
GROUP BY year
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;heterogeneous-and-nested-data&quot;&gt;Heterogeneous and nested data&lt;/h1&gt;

&lt;p&gt;But in real life, data is not always highly structured.&lt;/p&gt;

&lt;p&gt;First, data can be nested. Here is an example with arrays, but this can also be
with objects, and with an arbitrary depth.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{ &quot;Name&quot; : &quot;Peter&quot;, &quot;Year&quot; : [ 2015, 2014 ] }
{ &quot;Name&quot; : &quot;John&quot;, &quot;Year&quot; : [ 2013, 2018 ] }
{ &quot;Name&quot; : &quot;Helen&quot;, &quot;Year&quot; : [ 2012, 2017, 2019 ] }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The above input can be read into a dataframe like so:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Name (string)&lt;/th&gt;
      &lt;th&gt;Years (array of integers)&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Peter&lt;/td&gt;
      &lt;td&gt;[ 2015, 2014 ]&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;John&lt;/td&gt;
      &lt;td&gt;[ 2013, 2018 ]&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Helen&lt;/td&gt;
      &lt;td&gt;[ 2012, 2017, 2019 ]&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Nestedness can be handled by Spark SQL. Object lookup is done with dots, and Array lookup with the EXPLODE function like so:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;SELECT Name, EXPLODE(Years) as Year
FROM input
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;yielding the following dataframe&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Name (string)&lt;/th&gt;
      &lt;th&gt;Year (integer)&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Peter&lt;/td&gt;
      &lt;td&gt;2015&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Peter&lt;/td&gt;
      &lt;td&gt;2014&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;John&lt;/td&gt;
      &lt;td&gt;2013&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;John&lt;/td&gt;
      &lt;td&gt;2018&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Helen&lt;/td&gt;
      &lt;td&gt;2012&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Helen&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Helen&lt;/td&gt;
      &lt;td&gt;2019&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Even though having to explicitly do this conversion adds complexity, this may not feel yet like trying to feet a square peg (trees) in a round-shaped hole (a table).&lt;/p&gt;

&lt;p&gt;But this becomes more apparent when the data is heterogeneous, like so:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{ &quot;Name&quot; : &quot;Peter&quot;, &quot;Year&quot; : 2015 }
{ &quot;Name&quot; : &quot;John&quot;, &quot;Year&quot; : 2013 }
{ &quot;Name&quot; : &quot;Helen&quot;, &quot;Year&quot; : [ 2012, 2017, 2019 ] }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;where the Year field is fit into a attribute with the least common denominator type: string (quotes are used to make explicit that
we do not have integers and an array, but really three strings):&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Name (string)&lt;/th&gt;
      &lt;th&gt;Years (string)&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Peter&lt;/td&gt;
      &lt;td&gt;“2015”&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;John&lt;/td&gt;
      &lt;td&gt;“2013”&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Helen&lt;/td&gt;
      &lt;td&gt;”[ 2012, 2017, 2019 ]”&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;This puts a lot of burden on the user, who has to manually parse these strings back to whichever types make sense to them.&lt;/p&gt;

&lt;p&gt;In the real world, data can be heterogeneous: the rows may not have the same fields, some may be missing
some may be extra, and the types may be different. This happens, for example, when datasets are created over
decades of data gathering. The schema evolves, fields are added or removed, types are changed, but past
data does not, or cannot, get converted to the new schema.&lt;/p&gt;

&lt;h1 id=&quot;jsoniq-a-language-that-natively-processes-nested-heterogeneous-data&quot;&gt;JSONiq: a language that natively processes nested, heterogeneous data&lt;/h1&gt;

&lt;p&gt;JSONiq, which inherits 95% of its features from XQuery, a W3C standard, addresses these problems. Its
most useful expression, FLWOR, is the counterpart of SQL’s SELECT FROM WHERE, but more flexible.&lt;/p&gt;

&lt;p&gt;With a data model based on sequences of items, which can be homogeneous or heterogeneous or not, it deals
natively with nested and heterogeneous data.&lt;/p&gt;

&lt;p&gt;For example, we can query the above heterogeneous dataset even though the Year field may consist of integers
or arrays of integers, like so:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;for $person in json-file(&quot;people&quot;)
let $years := flatten($person.Year)
return { &quot;Name&quot; : $person.Name, &quot;NumberOfYears&quot; : count($years) }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Which gives the following result:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{ &quot;Name&quot; : &quot;Peter&quot;, &quot;NumberOfYears&quot; : 1 }
{ &quot;Name&quot; : &quot;John&quot;, &quot;NumberOfYears&quot; : 1 }
{ &quot;Name&quot; : &quot;Helen&quot;, &quot;NumberOfYears&quot; : 3 }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;FLWOR expressions support projection, selection, grouping, ordering, joining, couting (aka zipping), etc.&lt;/p&gt;

&lt;h1 id=&quot;rumble-pushing-down-the-computations-to-spark&quot;&gt;Rumble: pushing down the computations to Spark&lt;/h1&gt;

&lt;p&gt;Rumble is a JSONiq engine that processes heterogeneous, nested datasets with billions of JSON objects
by dynamically pushing down computations to Spark. The query above, for example, will be executed with
map() and flatMap() transformations, but this is all transparent to the user.&lt;/p&gt;

&lt;p&gt;We are now actively working on pushing down more features.&lt;/p&gt;

&lt;p&gt;For example, the following queries, even without using FLWOR expressions, are automatically pushed down to Spark,
but are significantly simpler and easier to write than using Spark RDDs or Spark SQL for this kind of dataset:&lt;/p&gt;

&lt;p&gt;Counting the number of objects in the dataset:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;count(json-file(&quot;people&quot;))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Discovering all the top-level keys in the dataset:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;keys(json-file(&quot;people&quot;))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Discovering all the distinct values of the field Name:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;distinct-values(json-file(&quot;people&quot;).Name)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Discovering all the distinct values of the years, whether nested in an array or not:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;distinct-values(flatten(json-file(&quot;people&quot;).Year))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;open-source-download&quot;&gt;Open-source download&lt;/h1&gt;

&lt;p&gt;Rumble is available for download under an Apache 2.0 license under &lt;a href=&quot;http://rumbledb.org&quot;&gt;http://rumbledb.org
&lt;/a&gt;. If you find a bug, miss a feature, a builtin function or a pushdown, let us know on the GitHub issues page and
we will gladly help.&lt;/p&gt;</content><author><name>Ghislain  Fourny</name></author><summary type="html">This is an introduction and motivation to the Rumble engine, in particular, how it addresses the limitations of dataframes and Spark SQL when the dataset is heterogeneous and nested.</summary></entry><entry><title type="html">The design and implementation of a lock-free ring-buffer with contiguous reservations</title><link href="blog.systems.ethz.ch/blog/2019/the-design-and-implementation-of-a-lock-free-ring-buffer-with-contiguous-reservations.html" rel="alternate" type="text/html" title="The design and implementation of a lock-free ring-buffer with contiguous reservations" /><published>2019-06-03T00:00:00+00:00</published><updated>2019-06-03T00:00:00+00:00</updated><id>blog.systems.ethz.ch/blog/2019/the-design-and-implementation-of-a-lock-free-ring-buffer-with-contiguous-reservations</id><content type="html" xml:base="blog.systems.ethz.ch/blog/2019/the-design-and-implementation-of-a-lock-free-ring-buffer-with-contiguous-reservations.html">&lt;p&gt;This is the story of how &lt;a href=&quot;https://twitter.com/bitshiftmask&quot;&gt;James Munns&lt;/a&gt; (from &lt;a href=&quot;https://ferrous-systems.com&quot;&gt;Ferrous Systems&lt;/a&gt;) and &lt;a href=&quot;https://twitter.com/utaal&quot;&gt;Andrea Lattuada&lt;/a&gt; (PhD student in the Systems Group) designed and implemented (two versions!) of an high-perf lock-free ring-buffer for cross-thread communication. If any of those words look scary to you, don’t fret, we’ll explain everything from the basics.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post is cross-posted on Ferrous Systems’ &lt;a href=&quot;https://ferrous-systems.com/blog/lock-free-ring-buffer/&quot;&gt;blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;This post is for you if you’re interested in (safe!) concurrency, systems programming, and cool ways to write efficient systems software. If you’ve never written a thread-safe data structure, this post may be a great way to get started!&lt;/p&gt;

&lt;h2 id=&quot;circular-buffers&quot;&gt;Circular buffers&lt;/h2&gt;

&lt;p&gt;A &lt;a href=&quot;https://www.codeproject.com/Articles/3479/The-Bip-Buffer-The-Circular-Buffer-with-a-Twist&quot;&gt;&lt;em&gt;BipBuffer&lt;/em&gt;&lt;/a&gt; is a bi-partite circular buffer that always supports writing a contiguous chunk of data, instead of potentially splitting a write in two chunks when it straddles the buffer’s boundaries.&lt;/p&gt;

&lt;p&gt;Circular buffers are a common primitive for asynchronous (inter- or intra- thread) communication. Let’s start with a very abstract, idealised view of the circular buffer interface, and then consider real-world constraints one by one, till we get to the &lt;em&gt;BipBuffer&lt;/em&gt; design.&lt;/p&gt;

&lt;h3 id=&quot;an-idealised-infinite-buffer&quot;&gt;An idealised infinite buffer&lt;/h3&gt;

&lt;p&gt;A writer (producer) and a reader (consumer) want to communicate, and have access to the same, contiguous, and infinite array. They both keep a bookmark of which part of the array they’ve (respectively) written and read. They start with these &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt; pointers aligned.&lt;/p&gt;

&lt;p&gt;When the writer wants to send data, it appends it after the &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt; pointer and then moves the pointer to the end of the newly written chunk. The reader inspects the &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt; pointer at its leisure (asynchronously). When the &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt; pointer has advanced further than the &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt; pointer, the reader can consume and act on the available data. Once that’s done, it moves the &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt; pointer forwards to keep track of which part of the buffer it has already processed.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/the-design-and-implementation-of-a-lock-free-ring-buffer-with-contiguous-reservations/jncR6qd.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The reader will never attempt to read past the &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt; pointer, because there’s no guarantee there’s valid data there (i.e. that the writer has put anything there). This also means that the &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt; pointer can never overtake &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt;. For now, we’re assuming an ideal memory system that’s always coherent and where writes are visible immediately and sequentially.&lt;/p&gt;

&lt;h3 id=&quot;a-bounded-circular-buffer&quot;&gt;A bounded circular buffer&lt;/h3&gt;

&lt;p&gt;Computers don’t have magic infinite buffers. We have to allocate a finite amount of memory to use for potentially infinite communication between the writer and reader. In a circular buffer, the &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt; pointer can wrap around the boundaries of the buffer when it reaches the end.&lt;/p&gt;

&lt;p&gt;When new data arrives and the &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt; pointer is close to the end, it splits the write in two chunks: one for the remaining buffer space at the end, and one for the remaining data at the beginning. Note that, if the &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt; pointer is still close to the beginning, this has the potential of clobbering data that hasn’t yet been processed by the reader. For this reason, the &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt; pointer is not allowed to overtake &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt; after it has wrapped around.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/the-design-and-implementation-of-a-lock-free-ring-buffer-with-contiguous-reservations/zfwNfD0.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We end up with two possible memory configurations:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt; leads and &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt; follows (&lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt; ≥ &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt;), the valid data (written, but not yet processed by the reader) is in the section of the buffer after &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt; and before &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt;;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt; leads and &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt; follows (&lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt; &amp;gt; &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt;), the valid data is after &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt;, till the end, and from the start of the buffer till &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Note that we disallow &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt; == &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt; in the second case, as this would be ambiguous: while &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt; can catch up to &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt;, after a wraparound &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt; has to stay one step behind &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt; to indicate that we’re in case 2 instead of case 1.&lt;/p&gt;

&lt;p&gt;We repeatedly move from configuration 1 to 2, then back to 1: when &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt; reaches the end of the buffer, it can also wrap around to continue reading at the start.&lt;/p&gt;

&lt;h3 id=&quot;contiguous-writesreads&quot;&gt;Contiguous writes/reads&lt;/h3&gt;

&lt;p&gt;This is all great, but what if we have chunks of data that should remain contiguous in memory when written to the buffer? Look here, there’s a new message to be written, but it doesn’t fit in the remaining buffer space after &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/the-design-and-implementation-of-a-lock-free-ring-buffer-with-contiguous-reservations/szHSC8M.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If, for whatever reason, we aren’t allowed to split this write in two, we’re stuck. Maybe we can just wait for &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt; to move forwards, and place our new data in a single chunk at the start of the buffer? Well, in fact, yea. But there’s a caveat.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/the-design-and-implementation-of-a-lock-free-ring-buffer-with-contiguous-reservations/Lb8C3sq.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We’ve broken the property in configuration 2 earlier: there’s a section of the buffer that’s between &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt; and the end of the buffer, but doesn’t contain any valid data. If we didn’t do anything about it, the reader would keep consuming data, moving &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt; forwards, and it would be oblivious to the fact that at some point it would be reading a section of the buffer that doesn’t contain any valid information.&lt;/p&gt;

&lt;h2 id=&quot;a-hardware-interlude&quot;&gt;A Hardware Interlude&lt;/h2&gt;

&lt;p&gt;Previously we asked:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;What if we have chunks of data that should remain contiguous in memory when written to the buffer?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But when would we actually require that data be read or written to in a contiguous manner?&lt;/p&gt;

&lt;h3 id=&quot;dma---direct-memory-access&quot;&gt;DMA - Direct Memory Access&lt;/h3&gt;

&lt;p&gt;In embedded microcontroller systems, it is common to have a single core CPU. Instead of having multiple cores, they have a set of features referred to as Memory Mapped Peripherals. These Peripherals act as hardware accelerators for specific behaviors, such as sending or receiving data from a serial port.&lt;/p&gt;

&lt;p&gt;In order to minimize the amount of time necessary for the CPU to manually copy data from one place to another, these Peripherals can be configured to perform an action completely autonomously, streaming data to or from a section of memory on the CPU. This action of the hardware directly reading from or writing to the memory is called DMA, or Direct Memory Access.&lt;/p&gt;

&lt;p&gt;Instead of reading or writing one byte at a time to the Serial Port, the CPU can instead start the transfer, and when it is complete, process a chunk of bytes at a time. This allows for less time waiting, and is generally a more efficient method of processing data.&lt;/p&gt;

&lt;p&gt;A typical usage of DMA (called a DMA transaction) looks like this:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The CPU allocates N bytes of memory to be used for DMA&lt;/li&gt;
  &lt;li&gt;The CPU instructs the peripheral, such as a serial port, to receive N bytes of data, and to place those bytes in the memory allocated in step 1&lt;/li&gt;
  &lt;li&gt;Once the peripheral is configured, the CPU resumes performing other actions, and the Serial Port begins filling data into the memory buffer as it is received&lt;/li&gt;
  &lt;li&gt;When the Serial Port has received all N bytes requested, it notifies the CPU, and stops receiving data&lt;/li&gt;
  &lt;li&gt;The CPU may now process all N bytes requested, and if necessary, repeat the process at step one&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Although we often only have one CPU core in most microcontrollers, we can think of these DMA actors as their own thread. They are able to operate independently of the main CPU’s actions, and read and write memory based on their own needs. In these microcontroller systems, there can be tens or hundreds of these hardware actors, all operating in parallel!&lt;/p&gt;

&lt;h3 id=&quot;stackless-operation&quot;&gt;Stackless Operation&lt;/h3&gt;

&lt;p&gt;In step one of DMA procedure above, we talked about allocating N bytes of memory. On a non-embedded system, this would generally be done by allocating space on the heap - a &lt;code class=&quot;highlighter-rouge&quot;&gt;Box&lt;/code&gt; in Rust, or using &lt;code class=&quot;highlighter-rouge&quot;&gt;malloc()&lt;/code&gt; in C. In lightweight or timing critical embedded systems, it is uncommon to have a heap. Instead, all memory must be statically allocated, or allocated through the use of the stack.&lt;/p&gt;

&lt;p&gt;In these systems, data structures such as Circular Buffers are used to work around these limitations. A fixed amount of space is reserved for use, and a dynamic amount of data within a fixed maximum region is used to simulate a dynamic memory region.&lt;/p&gt;

&lt;p&gt;Unfortunately, these DMA transactions do not understand the concept of a circular buffer. They are only aware of a pointer to where the memory region starts, and how many bytes to use from the starting pointer. This means that a normal circular buffer where the data region could wrap around would not work for DMA transfers.&lt;/p&gt;

&lt;h3 id=&quot;but-why-is-dma-so-important&quot;&gt;But why is DMA so important?&lt;/h3&gt;

&lt;p&gt;For operations used with DMA, the speed at which bytes are transferred is often many orders of magnitude slower than the operation of the CPU itself. For a 32 bit ARM CPU, copying 4 bytes from RAM takes a single cycle. In a 64MHz CPU, this means it will take 15.6 nanoseconds to copy these four bytes.&lt;/p&gt;

&lt;p&gt;A typical serial port configuration is “115200 8N1”, which means 115,200 baud (or raw bits on the wire per second), with no parity, and 1 stop bit. This means that for every data byte sent, there will be 8 data bits, 1 unused parity bit, and 1 stop bit, to signal the end of the byte, sent over the wire.&lt;/p&gt;

&lt;p&gt;This means that we will need 40 bits on the wire to receive a 4 data bytes. At 115,200 bits on the wire per second, this means it will take 347,220 nanoseconds to receive the same four bytes, taking &lt;strong&gt;22,222 times as long&lt;/strong&gt; as it takes our CPU to copy the same amount of data!&lt;/p&gt;

&lt;p&gt;Instead of making our CPU waste all of this time waiting around, we allow the hardware to manage the simple sending and receiving process, allowing our CPU to either process other important tasks, or go into sleep mode, saving power or battery life.&lt;/p&gt;

&lt;h3 id=&quot;from-embedded-to-datacenters&quot;&gt;From embedded to datacenters&lt;/h3&gt;

&lt;p&gt;People writing high-performance application for datacenter grade servers have long realised this is also true for the high-grade, power-hungry CPUs they use.&lt;/p&gt;

&lt;p&gt;Modern, efficient network stacks for servers use similar DMA techniques to offload all of this work to the network card, so that valuable CPU time can be spent running data-crunching applications.&lt;/p&gt;

&lt;h3 id=&quot;a-fork-in-the-road&quot;&gt;A fork in the road&lt;/h3&gt;

&lt;p&gt;Here’s where the original BipBuffer design decides to maintain two “regions” of valid data, one at the start and one at the end of the buffer: this way it can keep track of which sections of the buffers contain valid data. Have a look at the &lt;a href=&quot;https://www.codeproject.com/Articles/3479/The-Bip-Buffer-The-Circular-Buffer-with-a-Twist&quot;&gt;BipBuffer&lt;/a&gt; blog post on CodeProject for details on how this works.&lt;/p&gt;

&lt;p&gt;The design based on two regions works great in a single threaded environment, but requires swapping the references to two regions when the rightmost one is depleted. This is tricky to do without explicit locking (mutexes) for cases in which the writer and reader reside on different threads.&lt;/p&gt;

&lt;p&gt;Our use case is communication between two concurrent threads of control: either two actual OS threads, or a main thread of control and an interrupt handler in embedded or a device driver. This is where our design takes inspiration from the &lt;em&gt;BipBuffer&lt;/em&gt;, but goes in a different direction.&lt;/p&gt;

&lt;h2 id=&quot;concurrency-design&quot;&gt;Concurrency design&lt;/h2&gt;

&lt;p&gt;A common strategy to reduce the amount of coordination that needs to happen between the two threads (writer, reader) is to associate each coordination variable (pointer) with a single thread that has exclusive write access to it. This also happens to simplify reasoning about the design, because it’s always clear who’s in charge of changing which variable.&lt;/p&gt;

&lt;p&gt;So, let’s start with a simple circular buffer that has the &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt; pointers from before. The writer is the only one who ever changes &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt;, and the reader is the only one who increments &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/the-design-and-implementation-of-a-lock-free-ring-buffer-with-contiguous-reservations/zfwNfD0.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So far so good. Each thread is only concerned with writing to one variable, and reading from the other.&lt;/p&gt;

&lt;h3 id=&quot;high-watermark-for-data&quot;&gt;High watermark for data&lt;/h3&gt;

&lt;p&gt;Now let’s re-introduce the requirement that the data written may need to be contiguous. If there’s no space available at the end of the buffer, the writer wraps around and writes the whole contiguous chunk at the start.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/the-design-and-implementation-of-a-lock-free-ring-buffer-with-contiguous-reservations/Lb8C3sq.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As we’ve seen, we need a way to tell the reader which part of the buffer is valid, and which was skipped to be able to write a single contiguous chunk. We’re tracking the high watermark of valid data in the buffer, so what about a &lt;code class=&quot;highlighter-rouge&quot;&gt;watermark&lt;/code&gt; pointer that gets written when the writer wraps around and leaves empty space at the end?&lt;/p&gt;

&lt;p&gt;Going back to our idealised infinite buffer from before, here’s what things would look like. Whenever the valid region isn’t split in two parts (at the beginning and end of the actual buffer) we simply need to track the write and read pointers, as before. On the other hand, when valid data wraps around the buffer, we leave an artificial “hole” in the “infinite buffer” representation. The &lt;code class=&quot;highlighter-rouge&quot;&gt;watermark&lt;/code&gt; lets us keep track of where the “hole” starts, and the end of the physical buffers marks the end.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/the-design-and-implementation-of-a-lock-free-ring-buffer-with-contiguous-reservations/lZrudcU.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;implementation&quot;&gt;Implementation&lt;/h2&gt;

&lt;p&gt;We have all the necessary elements for our non-blocking implementation. We start with the &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt; pointers aligned at the start of the buffer and the &lt;code class=&quot;highlighter-rouge&quot;&gt;watermark&lt;/code&gt; aligned with the end.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/the-design-and-implementation-of-a-lock-free-ring-buffer-with-contiguous-reservations/nS0tBm1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ContiguousAsyncBuffer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AtomicUsize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AtomicUsize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;watermark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AtomicUsize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We use &lt;code class=&quot;highlighter-rouge&quot;&gt;AtomicUsize&lt;/code&gt; to let the two threads read and update the pointers concurrently and safely. The writer/sender thread is in charge of &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;watermark&lt;/code&gt;, the reader/receiver is in charge of &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt;. This is important! Contended writes from multiple threads on the same memory location are a lot harder for the CPU’s cache coherence protocol to handle, and will cost latency and throughput.&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;
What’s more, it’s a lot easier to reason about correctness of these concurrent protocols if each of the shared pointers are always written by a certain thread (their “owner”).&lt;/p&gt;

&lt;h3 id=&quot;writing&quot;&gt;Writing&lt;/h3&gt;

&lt;p&gt;As long as there’s enough contiguous buffer space before the end of the physical buffer, as new data arrives (of length &lt;code class=&quot;highlighter-rouge&quot;&gt;write_len&lt;/code&gt;) the sender thread moves the &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt; pointer forwards to signal that a new chunk of the buffer is now valid and can be read.&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// [writer thread]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.write&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.write&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;write_len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When new data arrives and the &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt; pointer is close to the end, it moves the watermark to its current location, then wraps around. Again, if the &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt; pointer is still close to the beginning, this has the potential of clobbering data that hasn’t yet been processed by the reader. For this reason, the &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt; pointer is not allowed to overtake &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt; after it has wrapped around.&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// [writer thread]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.len&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.saturating_sub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.write&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;write_len&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;// not shown: check `read` to make sure there's enough free room&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.watermark&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.write&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;write_len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.write&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.write&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;write_len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// not enough space, wrap around&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;// not shown: check `read` to make sure there's enough free room at the beginning of the buffer&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.watermark&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.write&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.write&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;write_len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You may have noticed that the writer also pushes the &lt;code class=&quot;highlighter-rouge&quot;&gt;watermark&lt;/code&gt; forward when there’s room at the end of the buffer. We need to do this because we may have moved it back on a previous wrap-around and we want to avoid the reader now misinterpreting it as a sign that there’s a “hole” at the end.&lt;/p&gt;

&lt;h3 id=&quot;reading&quot;&gt;Reading&lt;/h3&gt;

&lt;p&gt;We end up again with two possible memory configurations:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt; leads and &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt; follows (&lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt; ≥ &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt;), the valid data (written, but not yet processed by the reader) is in the section of the buffer after &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt; and before &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt;;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt; leads and &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt; follows (&lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt; &amp;gt; &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt;), the valid data is after &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt;, till the &lt;code class=&quot;highlighter-rouge&quot;&gt;watermark&lt;/code&gt;, and from the start of the buffer till &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/the-design-and-implementation-of-a-lock-free-ring-buffer-with-contiguous-reservations/vgqghy7.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This makes the reader thread’s logic simple: read till you hit the &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt; pointer, or the &lt;code class=&quot;highlighter-rouge&quot;&gt;watermark&lt;/code&gt;, and update the &lt;code class=&quot;highlighter-rouge&quot;&gt;read&lt;/code&gt; pointer accordingly.&lt;/p&gt;

&lt;h3 id=&quot;a-note-on-memory-ordering&quot;&gt;A note on memory ordering&lt;/h3&gt;

&lt;p&gt;Some of you may have noticed that all of our calls to &lt;code class=&quot;highlighter-rouge&quot;&gt;load&lt;/code&gt; don’t take arguments and our calls to &lt;code class=&quot;highlighter-rouge&quot;&gt;store&lt;/code&gt; take a single argument, the new value for the &lt;code class=&quot;highlighter-rouge&quot;&gt;AtomicBool&lt;/code&gt;. This isn’t valid code, of course. The real signatures take another argument: &lt;code class=&quot;highlighter-rouge&quot;&gt;ordering: Ordering&lt;/code&gt;.
This instructs llvm on how to emit the proper memory fences and &lt;code class=&quot;highlighter-rouge&quot;&gt;sync&lt;/code&gt; instructions to drive the cache coherence and synchronization mechanisms built into the CPUs.&lt;/p&gt;

&lt;p&gt;The safe thing to do here is to always choose &lt;code class=&quot;highlighter-rouge&quot;&gt;Ordering::SeqCst&lt;/code&gt;, “sequential consistency”, which provides the strongest guarantees. At the hardware level, on x86, due to the hardware design, anything other than &lt;code class=&quot;highlighter-rouge&quot;&gt;Ordering::Relaxed&lt;/code&gt; is equivalent to &lt;code class=&quot;highlighter-rouge&quot;&gt;SeqCst&lt;/code&gt;. On ARMv7/v8, things get more complicated. The compiler can also make use of this information for reordering when running optimization passes.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;We recommend reading up on &lt;a href=&quot;https://doc.rust-lang.org/std/sync/atomic/enum.Ordering.html&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;Ordering&lt;/code&gt;&lt;/a&gt; both in the rust doc and in the documentation for your platform. For the purpose of this post, just assume we used &lt;code class=&quot;highlighter-rouge&quot;&gt;Ordering::SeqCst&lt;/code&gt; everywhere. This is often good enough in practice, and switching to a weaker &lt;code class=&quot;highlighter-rouge&quot;&gt;Ordering&lt;/code&gt; is only necessary to squeeze out the last bit of performance.&lt;/p&gt;

&lt;p&gt;In Andrea’s implementation of the lock-free ring-buffer, &lt;a href=&quot;https://github.com/utaal/spsc-bip-buffer&quot;&gt;spsc-bip-buffer&lt;/a&gt;, some of the orderings are relaxed for performance. This has the downside that it can introduce subtle concurrency bugs that may only show up on some platform (ARM, for example): to be a bit more confident that everything’s still fine, Andrea’s has continous integation tests both on x86 and ARM.&lt;/p&gt;

&lt;h3 id=&quot;support-for-embedded-systems&quot;&gt;Support for embedded systems&lt;/h3&gt;

&lt;p&gt;In James’ implementation of the lock-free ring-buffer, &lt;a href=&quot;https://github.com/jamesmunns/bbqueue&quot;&gt;bbqueue&lt;/a&gt;, convenience interfaces are provided for statically allocating instances of the ring-buffer. The queue can be split into Producer and Consumer halves, allowing for use of one half in interrupt context, and the other half in non-interrupt (or a different interrupt) context.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:2&quot;&gt;
      &lt;p&gt;It may be important to cache-align these memory locations and make sure there’s only one per cache line to avoid &lt;a href=&quot;https://en.wikipedia.org/wiki/False_sharing&quot;&gt;false sharing&lt;/a&gt;. &lt;a href=&quot;https://github.com/utaal/spsc-bip-buffer&quot;&gt;spsc-bip-buffer&lt;/a&gt; uses &lt;code class=&quot;highlighter-rouge&quot;&gt;cache_line_size::CacheAligned&lt;/code&gt;: &lt;a href=&quot;https://github.com/utaal/spsc-bip-buffer/blob/master/src/lib.rs#L8-L10&quot;&gt;https://github.com/utaal/spsc-bip-buffer/blob/master/src/lib.rs#L8-L10&lt;/a&gt;. &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:1&quot;&gt;
      &lt;p&gt;Thanks to Ralf for pointing out that it’s not &lt;em&gt;just&lt;/em&gt; about the hardware. &lt;a href=&quot;https://www.reddit.com/r/rust/comments/bwr2yg/the_design_and_implementation_of_a_lockfree/eq1zcbk/&quot;&gt;https://www.reddit.com/r/rust/comments/bwr2yg/the_design_and_implementation_of_a_lockfree/eq1zcbk/&lt;/a&gt; &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</content><author><name>Andrea Lattuada (&lt;a href=&quot;https://twitter.com/utaal&quot;&gt;@utaal&lt;/a&gt;) and James Munns (&lt;a href=&quot;https://twitter.com/bitshiftmask&quot;&gt;@bitshiftmask&lt;/a&gt;)</name></author><summary type="html">This is the story of how James Munns and Andrea Lattuada designed and implemented (two versions!) of an high-perf lock-free ring-buffer for cross-thread communication. If any of those words look scary to you, don't fret, we'll explain everything from the basics.</summary></entry><entry><title type="html">Academics Should Build Their Own Computers to Advance Systems Research</title><link href="blog.systems.ethz.ch/blog/2019/academics-should-build-their-own-computers.html" rel="alternate" type="text/html" title="Academics Should Build Their Own Computers to Advance Systems Research" /><published>2019-05-13T00:00:00+00:00</published><updated>2019-05-13T00:00:00+00:00</updated><id>blog.systems.ethz.ch/blog/2019/academics-should-build-their-own-computers</id><content type="html" xml:base="blog.systems.ethz.ch/blog/2019/academics-should-build-their-own-computers.html">&lt;p&gt;&lt;a href=&quot;https://people.inf.ethz.ch/troscoe/&quot;&gt;Mothy&lt;/a&gt; was invited to write a post
for the ACM SIGARCH blog, and decided to talk about building hardware
designed specifically for system software &lt;em&gt;research&lt;/em&gt; (as opposed to
run commercial workloads).  You can check it out here: 
&lt;a href=&quot;https://www.sigarch.org/academics-should-build-their-own-computers-to-advance-systems-research/&quot;&gt;https://www.sigarch.org/academics-should-build-their-own-computers-to-advance-systems-research/&lt;/a&gt;&lt;/p&gt;</content><author><name>Timothy Roscoe</name></author><summary type="html">Mothy was invited to write a post for the ACM SIGARCH blog, and decided to talk about building hardware designed specifically for system software research (as opposed to run commercial workloads). You can check it out here: https://www.sigarch.org/academics-should-build-their-own-computers-to-advance-systems-research/</summary></entry><entry><title type="html">A fork() in the road</title><link href="blog.systems.ethz.ch/blog/2019/fork.html" rel="alternate" type="text/html" title="A fork() in the road" /><published>2019-04-20T00:00:00+00:00</published><updated>2019-04-20T00:00:00+00:00</updated><id>blog.systems.ethz.ch/blog/2019/fork</id><content type="html" xml:base="blog.systems.ethz.ch/blog/2019/fork.html">&lt;p&gt;&lt;a href=&quot;https://www.microsoft.com/en-us/research/people/baumann/&quot;&gt;Andrew Baumann&lt;/a&gt;, 
&lt;a href=&quot;https://www.cs.bu.edu/~jappavoo/jappavoo.github.com/index.html&quot;&gt;Jonathan Appavoo&lt;/a&gt;,
&lt;a href=&quot;https://www.bu.edu/eng/profile/orran-krieger/&quot;&gt;Orran Krieger&lt;/a&gt;, and
&lt;a href=&quot;https://people.inf.ethz.ch/troscoe/&quot;&gt;I&lt;/a&gt; 
have written a paper for 
&lt;a href=&quot;http://hotos19.sigops.org/&quot;&gt;Hot Topics in Operating Systems&lt;/a&gt; next month about the Unix &lt;code class=&quot;highlighter-rouge&quot;&gt;fork()&lt;/code&gt; system call.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;fork()&lt;/code&gt; is roughly as old as I am - it was in the original version of
Unix - so it seems a bit odd to regard it as a “hot topic”.  &lt;a href=&quot;https://people.inf.ethz.ch/troscoe/pubs/hotos19_fork.pdf&quot;&gt;In the
paper&lt;/a&gt;
we argue that today it should be deprecated, for a variety of reasons.&lt;/p&gt;

&lt;p&gt;All four of us have been fascinated by &lt;code class=&quot;highlighter-rouge&quot;&gt;fork()&lt;/code&gt; for a long time.  We’ve
been involved in building various operating systems in industry and
academia for many years - including L4 (Andrew), Nemesis (Mothy),
Mungi (Andrew), Tornado (Orran, Jonathan), K42 (Orran, Jonathan,
Andrew), Barrelfish (Andrew, Mothy), and Drawbridge (Andrew) - none of
which really supported &lt;code class=&quot;highlighter-rouge&quot;&gt;fork()&lt;/code&gt; well, either by accident or design.
This was our attempt to get our collective thoughts down on paper, and
also reassess &lt;code class=&quot;highlighter-rouge&quot;&gt;fork()&lt;/code&gt; in the light of modern hardware.&lt;/p&gt;

&lt;p&gt;The reaction was interesting to say the least.  It’s
mostly died down by now, but it spurred some interesting discussion:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://lobste.rs/s/nfxsou/fork_road&quot;&gt;Lobster.rs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.reddit.com/r/programming/comments/bbic2e/a_fork_in_the_road/&quot;&gt;Reddit&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://lwn.net/Articles/785430/&quot;&gt;LWN.net&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://twitter.com/0xabU/status/1115726071364632576&quot;&gt;Twitter&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=19621799&quot;&gt;HackerNews&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A lot of these are interesting and highly informed takes on the paper,
sometimes agreeing, sometimes disagreeing, but often taking some quite
nuanced position in between.&lt;/p&gt;

&lt;p&gt;Orran also posted a great conversation
between him and his collaborator at Red Hat, Uli Drepper, about the
topic:&lt;/p&gt;

&lt;p&gt;https://www.bu.edu/rhcollab/2019/04/11/a-fork-in-the-road/&lt;/p&gt;

&lt;p&gt;The four of us feel pretty happy with how the paper turned out, but I
think it’s worth emphasizing a few points:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;We’re not Microsoft!  Andrew works at MSR, but the rest of us have
little connection with the company.  This paper is certainly not
representative of, or instigated by, Microsoft.&lt;/p&gt;

    &lt;p&gt;Quite a few comments assumed this was a “Microsoft whitepaper”,
whereas it’s actually an academic position paper written by 4
researchers who know each other, one of whom happens to be at MSR.
The rest of us are all at Universities.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We’re not dissing Unix!  Unix (and its clones) are an amazing
thing, and we all use it daily (I’m writing this on my Linux
laptop).  More than that, its safe to say that every new OS built
since the 1980s has been defined in reference to Unix, either
because it is more or less a copy of Unix architecturally, or
explicitly an attempt to do something different.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Unix was a minimalist, simple, elegant OS written in a short time by
people who deeply understood how these things work.  In this respect,
&lt;code class=&quot;highlighter-rouge&quot;&gt;fork()&lt;/code&gt; was a very minor piece of the puzzle - the
least-programming-effort way to create a new process by copying out
the state to swap in 27 assembly instructions.&lt;/p&gt;

&lt;p&gt;What I find fascinating is how, since then, &lt;code class=&quot;highlighter-rouge&quot;&gt;fork()&lt;/code&gt; has come to
dominate the OS.  As we show in the paper, in a modern Unix-like OS
like Linux or BSD, the semantics of &lt;code class=&quot;highlighter-rouge&quot;&gt;fork()&lt;/code&gt; touch and constrain the
design of every part of the kernel, and quite a bit of user space as
well.&lt;/p&gt;

&lt;p&gt;In a sense, today, Unix &lt;em&gt;is&lt;/em&gt; &lt;code class=&quot;highlighter-rouge&quot;&gt;fork()&lt;/code&gt; - once you’ve decided you want
&lt;code class=&quot;highlighter-rouge&quot;&gt;fork()&lt;/code&gt; to be fast, all the rest follows from good engineering
principles.&lt;/p&gt;

&lt;p&gt;Conversely, if you really want to explore an alternative OS design for
modern hardware, you have to give up on  &lt;code class=&quot;highlighter-rouge&quot;&gt;fork()&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I’m looking forward to Andrew’s presentation…&lt;/p&gt;</content><author><name>Timothy Roscoe</name></author><summary type="html">Andrew Baumann, Jonathan Appavoo, Orran Krieger, and I have written a paper for Hot Topics in Operating Systems next month about the Unix fork() system call.</summary></entry><entry><title type="html">String interning and beyond, in differential dataflow</title><link href="blog.systems.ethz.ch/blog/2018/string-interning-and-beyond.html" rel="alternate" type="text/html" title="String interning and beyond, in differential dataflow" /><published>2018-12-10T00:00:00+00:00</published><updated>2018-12-10T00:00:00+00:00</updated><id>blog.systems.ethz.ch/blog/2018/string-interning-and-beyond</id><content type="html" xml:base="blog.systems.ethz.ch/blog/2018/string-interning-and-beyond.html">&lt;p&gt;Differential dataflow does a great number of interesting bits of data processing, but what about when you want to use complicated types, like strings? In this post we’ll check out how to use differential dataflow to &lt;em&gt;intern&lt;/em&gt; strings, replacing them with integer identifiers that will allow the rest of our computation to execute more efficiently. From there, we’ll see how this generalizes to automatically assigning distinct record identifiers to collection elements, much like a database does!&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;As it has been a while, &lt;a href=&quot;https://github.com/frankmcsherry/differential-dataflow&quot;&gt;differential dataflow&lt;/a&gt; is a sweet programming framework which automatically updates its computations when you change its inputs. It goes really fast, scales, does twenty-seven things no other systems can do, blah blah.&lt;/p&gt;

&lt;p&gt;In the course of using differential dataflow, you may find yourself using types that contain strings. In &lt;a href=&quot;https://github.com/frankmcsherry/differential-dataflow/tree/master/doop&quot;&gt;one recent, interesting case of program analysis&lt;/a&gt;, the input records look like tab-separated lines of text:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;sun.font.SunFontManager$14: void &amp;lt;init&amp;gt;()&amp;gt; &amp;lt;init&amp;gt;  ()  sun.font.SunFontManager$14  void    ()V 0
&amp;lt;sun.awt.image.VSyncedBSManager$SingleVSyncedBSMgr: void &amp;lt;init&amp;gt;()&amp;gt;  &amp;lt;init&amp;gt;  ()  sun.awt.image.VSyncedBSManager$SingleVSyncedBSMgr   void    ()V 0
&amp;lt;javax.swing.AbstractAction: boolean shouldReconfigure(java.beans.PropertyChangeEvent)&amp;gt; shouldReconfigure   (java.beans.PropertyChangeEvent)    javax.swing.AbstractAction  boolean (Ljava/beans/PropertyChangeEvent;)Z 1
&amp;lt;sun.font.SunFontManager$14: void &amp;lt;init&amp;gt;()&amp;gt; &amp;lt;init&amp;gt;  ()  sun.font.SunFontManager$14  void    ()V 0
...
&amp;lt;java.awt.geom.AffineTransform: void transform(double[],int,double[],int,int)&amp;gt;  transform   (double[],int,double[],int,int) java.awt.geom.AffineTransform   void    ([DI[DII)V  5
&amp;lt;java.awt.geom.AffineTransform: void transform(double[],int,double[],int,int)&amp;gt;  transform   (double[],int,double[],int,int) java.awt.geom.AffineTransform   void    ([DI[DII)V  5
&amp;lt;java.awt.geom.AffineTransform: void transform(double[],int,double[],int,int)&amp;gt;  transform   (double[],int,double[],int,int) java.awt.geom.AffineTransform   void    ([DI[DII)V  5
...
&amp;lt;org.gjt.sp.jedit.pluginmgr.MirrorList: void readXml()&amp;gt; readXml ()  org.gjt.sp.jedit.pluginmgr.MirrorList   void    ()V 0
&amp;lt;sun.nio.cs.StandardCharsets$Aliases: void init(java.lang.Object[])&amp;gt;    init    (java.lang.Object[])    sun.nio.cs.StandardCharsets$Aliases void    ([Ljava/lang/Object;)V  1
&amp;lt;sun.nio.cs.StandardCharsets$Aliases: void init(java.lang.Object[])&amp;gt;    init    (java.lang.Object[])    sun.nio.cs.StandardCharsets$Aliases void    ([Ljava/lang/Object;)V  1
&amp;lt;org.gjt.sp.jedit.pluginmgr.MirrorList: void readXml()&amp;gt; readXml ()  org.gjt.sp.jedit.pluginmgr.MirrorList   void    ()V 0
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Barf.&lt;/p&gt;

&lt;p&gt;These particular records have a type that is in essence an array of strings six-long, &lt;code class=&quot;highlighter-rouge&quot;&gt;[String; 6]&lt;/code&gt;, and we need to perform maps, filters, joins, grouping, and even fixed-point iteration, all using types like this (likely with other values of &lt;code class=&quot;highlighter-rouge&quot;&gt;6&lt;/code&gt;).&lt;/p&gt;

&lt;h2 id=&quot;strings-do-work&quot;&gt;Strings do work!&lt;/h2&gt;

&lt;p&gt;Before going anywhere too exotic, like Fiji (sigh), the &lt;code class=&quot;highlighter-rouge&quot;&gt;String&lt;/code&gt; type totally works in differential dataflow. You can go and do graph computations where the node type is &lt;code class=&quot;highlighter-rouge&quot;&gt;String&lt;/code&gt;, or &lt;code class=&quot;highlighter-rouge&quot;&gt;(Vec&amp;lt;String&amp;gt;, bool)&lt;/code&gt;, or whatever crazy types you kids use to do your graph processing in Javascript (lol, I know… “types”).&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;String&lt;/code&gt; type works but it can be a bit inefficient when compared to something like &lt;code class=&quot;highlighter-rouge&quot;&gt;usize&lt;/code&gt;, which is just a much simpler type to work with when we want to hash-distribute records, or sort records, or group them by keys. It is also much more efficient to clone a &lt;code class=&quot;highlighter-rouge&quot;&gt;usize&lt;/code&gt; than a &lt;code class=&quot;highlighter-rouge&quot;&gt;String&lt;/code&gt;—the latter means we must allocate some memory and most likely de-allocate it at some future point—and generally even using &lt;code class=&quot;highlighter-rouge&quot;&gt;String&lt;/code&gt; types means we have some memory indirection along our critical path (farewell, branchless sort performance!).&lt;/p&gt;

&lt;h2 id=&quot;interning-strings&quot;&gt;Interning Strings&lt;/h2&gt;

&lt;p&gt;While &lt;code class=&quot;highlighter-rouge&quot;&gt;String&lt;/code&gt; works, it might be interesting to perform something like &lt;a href=&quot;https://en.wikipedia.org/wiki/String_interning&quot;&gt;string interning&lt;/a&gt;, in which each of the string instances is replaced by one representative, deduplicating the actual strings (allocations) being used.&lt;/p&gt;

&lt;p&gt;Let’s try something same same, but different: replacing each string with a unique integer identifier. We do lose the ability to do string-y operations, like substrings and converting to upper and lower case, but we can still do equality testing and hash-distribution and many of the core things we need to do in our data-parallel compute lifestyle.&lt;/p&gt;

&lt;p&gt;In the context of the program analysis project linked above, we can still execute Datalog programs, as they only really care about exact matches between fields.&lt;/p&gt;

&lt;p&gt;Single-threaded, string replacement would be super easy:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;/// Ensure `string` exists in `map`, return unique identifier.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;intern_in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HashMap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;.or_insert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Whenever we intern a string, we either return its existing identifier or add it with a new distinct identifier and then return that.&lt;/p&gt;

&lt;p&gt;This skips a few fun issues like do we ever &lt;em&gt;remove&lt;/em&gt; interned strings (not here), how to we look up strings from their identifiers (a second map, I guess), can we do this in parallel, and maybe a few other issues.&lt;/p&gt;

&lt;p&gt;We aren’t going to stick with this approach, but it is good to see that it isn’t all that painful.&lt;/p&gt;

&lt;h2 id=&quot;interning-strings-in-differential-dataflow&quot;&gt;Interning Strings &lt;em&gt;IN DIFFERENTIAL DATAFLOW&lt;/em&gt;&lt;/h2&gt;

&lt;p&gt;Let’s write a fairly simple computation that will intern strings using differential dataflow.&lt;/p&gt;

&lt;p&gt;Can’t we just use the above single-threaded fragment? Sure, sure. I did that in the project linked up above. It works, it’s totally fine, but it just feels a bit gross and non-robust. For example, we have to do all of the data loading on one thread, because we can’t intern the strings in parallel. If the set of strings changes dramatically, we keep all of the pre-existing strings around grotting up the place. Also c’mon, this is going to be neat and you might learn something. :D&lt;/p&gt;

&lt;p&gt;As a first, guess, couldn’t we just intern strings by hashing each of them and using the hash as the integer identifier? Almost, but there could be collisions. How about, if there are collisions, we pick one winner and re-hash the others until they don’t collide?&lt;/p&gt;

&lt;p&gt;Bingo!&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;/// Assigns a unique identifier to each element of `collection`.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;intern&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;G&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Collection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;G&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Collection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;G&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;where&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;G&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nn&quot;&gt;G&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Timestamp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Lattice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;// initialize each string at &quot;round&quot; zero.&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;.map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;.iterate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;c&quot;&gt;// propose a candidate hash from (round, string),&lt;/span&gt;
            &lt;span class=&quot;c&quot;&gt;// group by hash and pick at most one winner,&lt;/span&gt;
            &lt;span class=&quot;c&quot;&gt;//       defer non-winners to the next round.&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.hashed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
                &lt;span class=&quot;nf&quot;&gt;.group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;c&quot;&gt;// first (round, string) wins!&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.clone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
                    &lt;span class=&quot;c&quot;&gt;// if any losers, increment their rounds.&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.iter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(((&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.clone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
                &lt;span class=&quot;nf&quot;&gt;.map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;.map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.hashed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This works great. Each string in &lt;code class=&quot;highlighter-rouge&quot;&gt;collection&lt;/code&gt; gets a fairly random hash in round zero, and if there are any collisions we pick a winner (the earliest round, breaking ties lexicographically by string) and promote the losers to the next round. We don’t really expect many collisions, and we really don’t expect any one string to repeatedly collide with other strings (assuming our &lt;code class=&quot;highlighter-rouge&quot;&gt;.hashed()&lt;/code&gt; method is worth anything).&lt;/p&gt;

&lt;p&gt;What happens when we have a change in our input strings?&lt;/p&gt;

&lt;p&gt;Not very much, which is great news! There was so little interaction of strings, that there are similarly sparse changes to their interactions. Perhaps we could add a string that evicts a winner, but the cascade should be quite limited. Perhaps when we remove a winner we end up finding the string or two it collided with and re-naming them winner. But, most of the time we add or remove a string and its hash value as an identifier.&lt;/p&gt;

&lt;p&gt;This is all incrementalized, distributed, streaming, self-compacting, all that good technology that went into doing high-throughput graph computation, now assigning distinct numbers for your strings.&lt;/p&gt;

&lt;h2 id=&quot;using-interned-strings&quot;&gt;Using interned strings&lt;/h2&gt;

&lt;p&gt;Way back up there we had some horrible &lt;code class=&quot;highlighter-rouge&quot;&gt;[String; 6]&lt;/code&gt; folks that reminded us about Java and that evil still walks the Earth. How do we wire together a string interning fragment (like just above) with our stream of Java six-tuples?&lt;/p&gt;

&lt;p&gt;I’ll show you a pretty naive version, and I’ll sketch a more sophisticated version for your homework!&lt;/p&gt;

&lt;p&gt;The most naive way to do things is to i. extract the candidate strings to intern, and then ii. repeatedly join the six-tuples with the interned strings to extract identifiers for each coordinate at a time.&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// Each six-tuple offers six strings to intern.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;interned&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;intern&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;six_tuples&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.flat_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;interned_six&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;six_tuples&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// map each to (next_key, ([hashes], [strings])).&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;([],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])))&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.join_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interned&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])))&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.join_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interned&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])))&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.join_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interned&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])))&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.join_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interned&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])))&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.join_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interned&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])))&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.join_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interned&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ok, now all those &lt;code class=&quot;highlighter-rouge&quot;&gt;join_map&lt;/code&gt; closures aren’t actually legit Rust, but I hope you get the gist about what is going on. Six times, we extract the first remaining string and use &lt;code class=&quot;highlighter-rouge&quot;&gt;join_map&lt;/code&gt; to find us an integer hash value to replace it, and keep the remaining strings.&lt;/p&gt;

&lt;h2 id=&quot;arrangements&quot;&gt;Arrangements&lt;/h2&gt;

&lt;p&gt;As a quick aside, let’s recall that differential dataflow has a concept of an “Arrangement”, which is an indexed representation of a collection that can be re-used without additional cost. In the code above, each time we use &lt;code class=&quot;highlighter-rouge&quot;&gt;interned&lt;/code&gt; we re-build an index of the data, and we maintain the six copies as &lt;code class=&quot;highlighter-rouge&quot;&gt;interned&lt;/code&gt; changes.&lt;/p&gt;

&lt;p&gt;We can skip this by arranging &lt;code class=&quot;highlighter-rouge&quot;&gt;interned&lt;/code&gt; once and re-using the arrangement, like so:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// Each six-tuple offers six strings to intern.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;interned&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;intern&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;six_tuples&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.flat_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.arrange_by_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;interned_six&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;six_tuples&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// map each to (next_key, ([hashes], [strings])).&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;([],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])))&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.join_core&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interned&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)|&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))))&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.join_core&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interned&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)|&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))))&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.join_core&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interned&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)|&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))))&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.join_core&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interned&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)|&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))))&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.join_core&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interned&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)|&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))))&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.join_core&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interned&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)|&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Technically a few other things changed. We use &lt;code class=&quot;highlighter-rouge&quot;&gt;join_core&lt;/code&gt; rather than &lt;code class=&quot;highlighter-rouge&quot;&gt;join_map&lt;/code&gt; because that is the method that consumes arranged inputs (and it wants something like an iterator for output, even though we have just output for each match). But, this will maintain just one copy of &lt;code class=&quot;highlighter-rouge&quot;&gt;interned&lt;/code&gt; and re-use it six times!&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Intermission&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It was at this point that I proposed some homework. The industrious reader was invited to take the recently introduce &lt;a href=&quot;https://github.com/frankmcsherry/differential-dataflow/tree/master/dogsdogsdogs&quot;&gt;sweet join tech&lt;/a&gt; to try and perform those joins above without maintaining six copies of the the &lt;code class=&quot;highlighter-rouge&quot;&gt;six_tuples&lt;/code&gt; collection, each with progressively fewer strings and more integers.&lt;/p&gt;

&lt;p&gt;Let’s return to our story, and see where the author goes next.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;update-the-next-day&quot;&gt;Update (“The next day”)&lt;/h2&gt;

&lt;p&gt;Hey I tried that homework up above. I bet you did too, right? Pretty hard, huh?&lt;/p&gt;

&lt;p&gt;Despite being pretty sure that the &lt;code class=&quot;highlighter-rouge&quot;&gt;dogsdogsdogs&lt;/code&gt; project has positive implications, I think you still need to keep around the original &lt;code class=&quot;highlighter-rouge&quot;&gt;[String; 6]&lt;/code&gt; data somewhere, because if any string identifiers change you’ll need to push the changed &lt;code class=&quot;highlighter-rouge&quot;&gt;[usize; 6]&lt;/code&gt; records.&lt;/p&gt;

&lt;p&gt;Of course, if we naively indexed each &lt;code class=&quot;highlighter-rouge&quot;&gt;[String; 6]&lt;/code&gt; keyed by each of the six fields we are actually doing &lt;em&gt;worse&lt;/em&gt; than above, recording each string six times. So, that sucks. How do we avoid keeping six copies (or more, for numbers larger than six) of the input data around indexed different ways?&lt;/p&gt;

&lt;p&gt;How do real databases do this? Can we not just steal from them?&lt;/p&gt;

&lt;p&gt;Yes we can.&lt;/p&gt;

&lt;h2 id=&quot;row-identifiers-in-differential-dataflow&quot;&gt;Row Identifiers &lt;em&gt;IN DIFFERENTIAL DATAFLOW&lt;/em&gt;&lt;/h2&gt;

&lt;p&gt;In a great many database systems and schemas, when you introduce new records to a relation that does not otherwise have a primary key, you automatically get an auto-incremented “row identifier” added in that acts as a primary key. This row identifier lets you speak about the rows without slogging all of their data around all over the place. When performing joins and such a database system can just track the row identifiers involved (and perhaps the subset of attributes) rather than the potentially kilobytes of per-record payload.&lt;/p&gt;

&lt;p&gt;Let’s do that &lt;em&gt;IN DIFFERENTIAL DATAFLOW&lt;/em&gt;!&lt;/p&gt;

&lt;p&gt;Specifically, let’s assign row identifiers in differential dataflow &lt;em&gt;so that we can more efficiently intern strings&lt;/em&gt;, but at the same time we’ll come up with a great way to implement relational joins. The first one is probably more important, right?&lt;/p&gt;

&lt;p&gt;Let’s imagine we start with some collection of string six-tuples:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;horror&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Collection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and what we want most is to assign unique identifiers to each six-tuple.&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// Use the string interning method up above.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;horror_ids&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;intern&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;horror&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Yeah, it turns out we already invented it. Oops. !#$!ing generic programming.&lt;/p&gt;

&lt;h2 id=&quot;decomposing-records&quot;&gt;Decomposing records&lt;/h2&gt;

&lt;p&gt;We are now sitting on records of the form &lt;code class=&quot;highlighter-rouge&quot;&gt;([String; 6], usize)&lt;/code&gt;. What comes next?&lt;/p&gt;

&lt;p&gt;Next, let’s break apart these six-tuples into six collections, one for each attribute, each containing elements of the type &lt;code class=&quot;highlighter-rouge&quot;&gt;(usize, String)&lt;/code&gt; corresponding to the record identifier and the value for its associated attribute.&lt;/p&gt;

&lt;p&gt;The first step is to break down our &lt;code class=&quot;highlighter-rouge&quot;&gt;([String; 6], usize)&lt;/code&gt; collection to one containing six &lt;code class=&quot;highlighter-rouge&quot;&gt;(usize, usize, String)&lt;/code&gt; records for each input record, announcing each attribute and row identifier, and the value. Then we’ll partition into six collections using the attribute identifier:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attr_row_value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;horror_ids&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.flat_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;horror&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)|&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;horror&lt;/span&gt;
            &lt;span class=&quot;nf&quot;&gt;.into_iter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;    &lt;span class=&quot;c&quot;&gt;// six-element iteration.&lt;/span&gt;
            &lt;span class=&quot;nf&quot;&gt;.enumerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;    &lt;span class=&quot;c&quot;&gt;// pre-pend with attr_id.&lt;/span&gt;
            &lt;span class=&quot;nf&quot;&gt;.map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Partition collections by attr_id (timely magic).&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attr_collections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Collection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;G&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;attr_row_value&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;.inner&lt;/span&gt;                  &lt;span class=&quot;c&quot;&gt;// inner timely stream&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.partition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.into_iter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.as_collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;.collect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We now have six collections. One for each attribute, each containing records like &lt;code class=&quot;highlighter-rouge&quot;&gt;(row_id, value)&lt;/code&gt;. That was amazingly fun, of course, but why did we do this?&lt;/p&gt;

&lt;p&gt;There are at least two reasons that I can think of, string interning and making joins go faster, let’s talk each of them out.&lt;/p&gt;

&lt;h3 id=&quot;string-interning&quot;&gt;String interning&lt;/h3&gt;

&lt;p&gt;Obviously this is why we are here. We are all about the strings.&lt;/p&gt;

&lt;p&gt;We can independently intern the strings in each of the six collections, like so:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attr_interned&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;attr_collections&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.iter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;
            &lt;span class=&quot;nf&quot;&gt;.map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
            &lt;span class=&quot;nf&quot;&gt;.join_core&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interned&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;.collect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Did you notice I used &lt;code class=&quot;highlighter-rouge&quot;&gt;join_core&lt;/code&gt;, which is the version that doesn’t re-index &lt;code class=&quot;highlighter-rouge&quot;&gt;interned&lt;/code&gt; and instead re-uses the common arrangement? :D&lt;/p&gt;

&lt;p&gt;This computation produces six collections each containing &lt;code class=&quot;highlighter-rouge&quot;&gt;(row_id, hash)&lt;/code&gt; pairs, and we can use those more-or-less as if they were &lt;code class=&quot;highlighter-rouge&quot;&gt;(row_id, value)&lt;/code&gt; pairs, almost. At the same time, it maintains each attribute value &lt;em&gt;once&lt;/em&gt;, in indexed form for the first input to &lt;code class=&quot;highlighter-rouge&quot;&gt;join_core&lt;/code&gt;. This is way better than six times.&lt;/p&gt;

&lt;p&gt;Technically we have an additional copy of each attribute value back where we determined record identifiers (that subcomputation stashes each of the argument records).&lt;/p&gt;

&lt;h3 id=&quot;making-joins-better&quot;&gt;Making joins better&lt;/h3&gt;

&lt;p&gt;Our decomposition of our relation into the attributes allows us to do a bit of a la carte columnar join processing, which can be fun.&lt;/p&gt;

&lt;p&gt;Let’s imagine that instead of just forming each of the &lt;code class=&quot;highlighter-rouge&quot;&gt;(row_id, value)&lt;/code&gt; collections we also &lt;code class=&quot;highlighter-rouge&quot;&gt;arrange&lt;/code&gt; each of them, resulting in a maintained collection indexed by &lt;code class=&quot;highlighter-rouge&quot;&gt;row_id&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attr_arrangeds&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;attr_collections&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.iter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.arrange_by_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;.collect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can now use these arrangements to re-assemble arbitrary subsets of attributes in the record, with surprisingly small cost.&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attrs_034&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;attr_arrangeds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.join_core&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attr_arrangeds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.join_core&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attr_arrangeds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The “surprisingly small” cost here (debatable) is because each of the collection arguments to &lt;code class=&quot;highlighter-rouge&quot;&gt;join_core&lt;/code&gt; is pre-arranged, meaning sorted by the key (&lt;code class=&quot;highlighter-rouge&quot;&gt;row_id&lt;/code&gt;). When &lt;code class=&quot;highlighter-rouge&quot;&gt;join_core&lt;/code&gt; gets to work, it does one sequential swing through each arrangement, picking up the attributes we are looking for.&lt;/p&gt;

&lt;p&gt;The attentive reader might complain that the first input to the &lt;em&gt;second&lt;/em&gt; &lt;code class=&quot;highlighter-rouge&quot;&gt;join_core&lt;/code&gt; operator is &lt;em&gt;not&lt;/em&gt; arranged, and will cost, and this is where we break out the &lt;a href=&quot;https://github.com/frankmcsherry/differential-dataflow/tree/master/dogsdogsdogs&quot;&gt;dogsdogsdogs&lt;/a&gt; delta queries. They use the arranged collections but don’t need to maintain intermediate collections (because they respond to change is e.g. &lt;code class=&quot;highlighter-rouge&quot;&gt;attr_arrangeds[4]&lt;/code&gt; with a different dataflow).&lt;/p&gt;

&lt;p&gt;We can also independently filter the attributes, and &lt;em&gt;then&lt;/em&gt; join. This allows us to tap dance through only the relevant records in each of the relations. For example, consider:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attrs_034&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;attr_collections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.join_core&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attr_arrangeds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.join_core&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attr_arrangeds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The arrangement going in to the first &lt;code class=&quot;highlighter-rouge&quot;&gt;join_core&lt;/code&gt; has been reduced, but the row identifiers are still in order. All off differential dataflow’s join operators are implemented to seek rather than scan between keys, and so a sparse set of filtered keys will allow the operator to zip forward through the keys in &lt;code class=&quot;highlighter-rouge&quot;&gt;attr_arrangeds[3]&lt;/code&gt;, rather than scanning all of them.&lt;/p&gt;

&lt;p&gt;This works less well once we’ve rocked things down to interned string identifiers, but .. well maybe this section should have come before that section. Still working on that.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;performance-update-a-few-days-later&quot;&gt;Performance Update (“A few days later”)&lt;/h2&gt;

&lt;p&gt;It turns out this computation led me down an interesting performance rabbit hole, and I’ve just returned with fabulous and wonderful stories!&lt;/p&gt;

&lt;p&gt;Let’s talk through the &lt;code class=&quot;highlighter-rouge&quot;&gt;intern&lt;/code&gt; function up above, and what it does. We will tease out a few performance issues, ones that you might not have even realized were in your power to fix (one still isn’t), and see things get a fair bit better by doing so.&lt;/p&gt;

&lt;h3 id=&quot;baseline-performance&quot;&gt;Baseline performance&lt;/h3&gt;

&lt;p&gt;The core of &lt;code class=&quot;highlighter-rouge&quot;&gt;intern&lt;/code&gt;’s iterative computation takes the full set of &lt;code class=&quot;highlighter-rouge&quot;&gt;(round, string)&lt;/code&gt; inputs we have and groups them by their candidate hash value, and produces winners and losers as output (where losers get their round incremented):&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.hashed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;.group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.clone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.iter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(((&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.clone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;.map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is all well and good. Let’s see how long it takes to intern 1,000,000 integers (not strings, sorry; but this is easier):&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Echidnatron% cargo run --release --example test -- 10000000
    Finished release [optimized + debuginfo] target(s) in 0.09s
     Running `target/release/examples/test 10000000`
12.505527384s
^C
Echidnatron%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Hard to know if this is particularly good (it’s about 1.25 microseconds per identifier). The process’s memory use stabilizes at 1.31GB which is around 131 bytes per identifier. That is a bit larger than we might expect.&lt;/p&gt;

&lt;p&gt;It turns out that our program is doing something silly, at least silly for this type of computation. Our &lt;code class=&quot;highlighter-rouge&quot;&gt;group&lt;/code&gt; operator receives inputs with largely distinct hash values, and for these inputs it simply reproduces them as output. To stay sane, the &lt;code class=&quot;highlighter-rouge&quot;&gt;group&lt;/code&gt; operator maintains both its input and output collections, so it maintains two nearly identical copies.&lt;/p&gt;

&lt;p&gt;Seems pretty natural, though. Unless we want to invent a new &lt;code class=&quot;highlighter-rouge&quot;&gt;group&lt;/code&gt; implementation, which we (I) don’t.&lt;/p&gt;

&lt;h3 id=&quot;switching-to-differences&quot;&gt;Switching to differences&lt;/h3&gt;

&lt;p&gt;Our computation determines the “new” pairs &lt;code class=&quot;highlighter-rouge&quot;&gt;(round, string)&lt;/code&gt; by incrementing the round field of a relatively small number of records. What if instead we asked &lt;code class=&quot;highlighter-rouge&quot;&gt;group&lt;/code&gt; to produce only the changes?&lt;/p&gt;

&lt;p&gt;What does that mean? Isn’t differential dataflow already incrementalized? Yes, yes, but I mean something different. What if we compute “how should we change &lt;code class=&quot;highlighter-rouge&quot;&gt;temp&lt;/code&gt; to avoid collisions?”, and then concatenate the results with &lt;code class=&quot;highlighter-rouge&quot;&gt;temp&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.hashed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;.group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;c&quot;&gt;// output.push((input[0].0.clone(), 1));&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.iter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(((&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.clone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()),&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(((&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.clone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;.map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;.concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It is a bit weird to do this ourselves, rather than asking differential dataflow to do it for us, but we are in the special situation where the &lt;code class=&quot;highlighter-rouge&quot;&gt;group&lt;/code&gt; operator has the same input as output, and we want to do input v. output differences, rather than time-by-time differences which differential does well.&lt;/p&gt;

&lt;p&gt;In some weird interpretation we are doing “spatial differencing” rather than “temporal differencing”, relating different locations in our dataflow. Never believe that just because someone has fancy names for things means they understand what is going on.&lt;/p&gt;

&lt;p&gt;For example, watch this:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Echidnatron% cargo run --release --example test -- 10000000
    Finished release [optimized + debuginfo] target(s) in 0.08s
     Running `target/release/examples/test 10000000`
15.039220586s
^C
Echidnatron%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That took longer. What a pity. On the other hand, it stabilizes at a memory footprint of just 578MB, which is about half the size of our prior attempt, which is a success! That is some 57.8 bytes per record, which is basically what we should expect given our data structures (seven eight byte records, including the hash, record, two offsets, a two-dimensional timestamp, and a difference).&lt;/p&gt;

&lt;p&gt;So what is going on that makes it go slower, despite using half the memory?&lt;/p&gt;

&lt;h3 id=&quot;optimizing-iteration&quot;&gt;Optimizing iteration&lt;/h3&gt;

&lt;p&gt;The short version (there is a longer version; it involved cursing) is:&lt;/p&gt;

&lt;p&gt;Our &lt;code class=&quot;highlighter-rouge&quot;&gt;iterate&lt;/code&gt; method develops all &lt;code class=&quot;highlighter-rouge&quot;&gt;(round, string)&lt;/code&gt; pairs, and so at some point (the beginning) we need to bring in these initial values, apply one step of our logic, and then subtract the initial values. We have to do this even when nothing changes, because we have to check that nothing has changed. When nothing changes this difference cancels and we don’t have anything to write down (yay!) but we had to do the work to determine this (oh well…).&lt;/p&gt;

&lt;p&gt;To work around this, we will need to write a different computation. A computation that doesn’t iteratively develop the full collection of &lt;code class=&quot;highlighter-rouge&quot;&gt;(round, string)&lt;/code&gt; pairs, but perhaps instead iteratively develops the changes needed to apply to the &lt;em&gt;initial&lt;/em&gt; &lt;code class=&quot;highlighter-rouge&quot;&gt;collection&lt;/code&gt; (rather than changes to &lt;code class=&quot;highlighter-rouge&quot;&gt;temp&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Here is how I wrote that:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;/// Assigns a unique identifier to each element of `collection`.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;intern&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;G&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Collection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;G&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Collection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;G&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;where&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;G&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nn&quot;&gt;G&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Timestamp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Lattice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// capture the initial (round, record) pairs.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;.iterate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;diff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;
            &lt;span class=&quot;c&quot;&gt;// Bring `init` into scope and add to `diff`.&lt;/span&gt;
            &lt;span class=&quot;c&quot;&gt;// Then determine changes relative to `init`,&lt;/span&gt;
            &lt;span class=&quot;c&quot;&gt;// which means subtracting records at round 0.&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.enter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;diff&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
                &lt;span class=&quot;nf&quot;&gt;.concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;diff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;nf&quot;&gt;.map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.hashed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
                &lt;span class=&quot;nf&quot;&gt;.group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;c&quot;&gt;// keep round-positive records as changes.&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;round&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(((&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.clone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()),&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(((&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.clone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()),&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                    &lt;span class=&quot;c&quot;&gt;// if any losers, increment their rounds.&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.iter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                        &lt;span class=&quot;c&quot;&gt;// Subtract a *round zero* instance of the record.&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(((&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.clone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()),&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(((&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.clone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()),&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
                &lt;span class=&quot;nf&quot;&gt;.map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;.concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// concat init *outside* the loop.&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;.map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hash&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.hashed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This computation develops what is very likely a &lt;em&gt;small&lt;/em&gt; collection &lt;code class=&quot;highlighter-rouge&quot;&gt;diff&lt;/code&gt;, although it does use &lt;code class=&quot;highlighter-rouge&quot;&gt;init&lt;/code&gt; which may be not small. Fortunately, it uses &lt;code class=&quot;highlighter-rouge&quot;&gt;init&lt;/code&gt; only once, in the input to &lt;code class=&quot;highlighter-rouge&quot;&gt;group&lt;/code&gt;. Further, as it does not start from &lt;code class=&quot;highlighter-rouge&quot;&gt;init&lt;/code&gt; (our &lt;code class=&quot;highlighter-rouge&quot;&gt;filter&lt;/code&gt; fixes that) we don’t end up wasting any time subtracting it back off.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Echidnatron% cargo run --release --example test -- 10000000
    Finished release [optimized + debuginfo] target(s) in 0.08s
     Running `target/release/examples/test 10000000`
6.519266834s
^C
Echidnatron%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This works out to 652 nanoseconds per record (sorting by hash, I think), and the memory footprint ends up at 621MB which is approximately what we had up above. Maybe a touch more for reasons I don’t currently understand, but good enough for us for now.&lt;/p&gt;

&lt;p&gt;We were very fortunate with this computation because it was possible to reason about changes relative to &lt;code class=&quot;highlighter-rouge&quot;&gt;init&lt;/code&gt;, as we knew that the only thing that happens to round counters is that they are incremented from zero. Our second implementation, slower but with a smaller footprint, is probably the more reasonable style of computation to expect people to be able to write for more general computations.&lt;/p&gt;</content><author><name>Frank McSherry (&lt;a href=&quot;https://twitter.com/frankmcsherry&quot;&gt;@frankmcsherry&lt;/a&gt;)</name></author><summary type="html">Differential dataflow does a great number of interesting bits of data processing, but what about when you want to use complicated types, like strings? In this post we’ll check out how to use differential dataflow to intern strings, replacing them with integer identifiers that will allow the rest of our computation to execute more efficiently. From there, we’ll see how this generalizes to automatically assigning distinct record identifiers to collection elements, much like a database does!</summary></entry><entry><title type="html">Physical Adressing on Real Hardware in Isabelle/HOL</title><link href="blog.systems.ethz.ch/blog/2018/phyiscal-adressing-on-real-hw.html" rel="alternate" type="text/html" title="Physical Adressing on Real Hardware in Isabelle/HOL" /><published>2018-11-09T00:00:00+00:00</published><updated>2018-11-09T00:00:00+00:00</updated><id>blog.systems.ethz.ch/blog/2018/phyiscal-adressing-on-real-hw</id><content type="html" xml:base="blog.systems.ethz.ch/blog/2018/phyiscal-adressing-on-real-hw.html">&lt;p&gt;Modern memory systems are much more complicated than the traditionally assumed
virtual and physical address space separation. We explain in this post which
effects can not solely expressed by the basic model and are important for
correct function of operating systems.  We summarize our recent &lt;a href=&quot;https://link.springer.com/chapter/10.1007/978-3-319-94821-8_1&quot;&gt;paper&lt;/a&gt;.
In this work we present a theory for addressing in such modern memory
subsystems. We formalize the theory in Isabelle/HOL.&lt;/p&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Today’s operating system, text books and also verification efforts assume a
quite simple memory model: Applications execute in a virtual address space,
virtual addresses get translated into the physical address space by a MMU. In
this physical address space the systems DRAM and memory mapped registers of
devices are located. If there are devices that perform direct memory accesses
(DMA), they access the physical address space directly. This model is depicted
in Figure 1.&lt;/p&gt;

&lt;div class=&quot;image&quot;&gt;
    &lt;img src=&quot;/assets/posts/2018-11-09-phyiscal-adressing-on-real-hw/naive-system.png&quot; width=&quot;100%&quot; /&gt;
    &lt;span&gt;Fig1. The traditional view of memory systems&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;However, on real systems this simplistic view fails to capture the necessary
details for correct operation. In a previous workshop paper we have 
discussed a variety of real systems and shown that more complicated systems
are indeed common. Let me show you one example to illustrate some effects
we encounter in Fig2.&lt;/p&gt;

&lt;div class=&quot;image&quot;&gt;
    &lt;img src=&quot;/assets/posts/2018-11-09-phyiscal-adressing-on-real-hw/omap-view.png&quot; width=&quot;100%&quot; /&gt;
    &lt;span&gt;Fig2. A real system (excerpt)&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;This figure shows how different cores can access the &lt;code class=&quot;highlighter-rouge&quot;&gt;GPT5&lt;/code&gt;, a memory mapped 
general purpose timer. The physical address that a core has to issue depends
on the core, the A9 core has two option of reaching the device, either using
the private interface to the timer using the base address &lt;code class=&quot;highlighter-rouge&quot;&gt;0x40138000&lt;/code&gt; or accessing
the timer through the &lt;code class=&quot;highlighter-rouge&quot;&gt;L3&lt;/code&gt; bus using the address &lt;code class=&quot;highlighter-rouge&quot;&gt;0x49038000&lt;/code&gt;. Address synonyms
(two addresses that access the same physical
location) are not expressible in the simplistic memory model.&lt;/p&gt;

&lt;p&gt;Accessing the same location from the &lt;code class=&quot;highlighter-rouge&quot;&gt;DSP&lt;/code&gt; is possible, but a different address
has to be used. The M3 core has to issue again a different address, even though
the memory accesses passes through the same interconnect. In such a system
it does not make sense anymore to talk about a physical address space, every
actor has its own view of the system. These effects are quite common, for
instance on x86 platforms each CPU has its own local APIC registers, 
that all appear under the same address.&lt;/p&gt;

&lt;h2 id=&quot;the-decoding-net&quot;&gt;The decoding net&lt;/h2&gt;
&lt;p&gt;Since the simplistic model is not powerful enough, we need something better.
We noted there is no physical address space anymore, hence the notion of a
physical or absolute address does not make sense anymore. Instead we focus
on talking about relative addresses. We call a relative
address plus the node on which this address is to be interpreted as &lt;i&gt;name&lt;/i&gt;.
The nodes in our system have two properties: They can accept addresses,
and they can translate addresses. To model caches which either
accept or translate, depending on the cache state, we permit addresses
that translate to multiple output addresses. Our system of nodes forms a directed graph.&lt;/p&gt;

&lt;p&gt;A natural question to ask is, where does a certain name end up when issued on
this node. A difficulty in this is that our system permits loops. A real system
that has memory addressing loops is probably faulty or misconfigured, but we do
not want to rule this out in our modeling approach. In fact, showing the
absence of such misconfiguration in any real system is one of our future tasks.
In the paper we give a set theoretic and an operational definition of the
resolve function. We show that they are equivalent, under the assumption that
the operational resolution actually terminates.  Because of this assumption, we
study under which conditions termination actually occurs.  The rank function
assigns each name a natural number and it must decrease every time a translate
step is taken. We found that specifying a rank function is a necessary and
sufficient condition for termination.&lt;/p&gt;

&lt;p&gt;While the decoding net captures the essential details, it is not a very handy
representation for use in an operating system. If we fix one observer,   we can
derive a simplified decoding net that resembles the two layer simplistic model.
We do so by collapsing all the translate steps into one. We formalized this
process and show that it preserves view-equivalency for the chosen observer.
View equivalent means that the same address resolves to the same address.&lt;/p&gt;

&lt;h2 id=&quot;model-refinement&quot;&gt;Model refinement&lt;/h2&gt;
&lt;p&gt;In a real operating system, we implement a data structure that refines the
decoding net. However, we also must populate this datastructure. How this is
done depends on the system we are running on. Certain platforms offer discovery
mechanisms, such as ACPI. On other platforms, this information can not be
discovered and must be provided by the operating system developer. In this
case, we need to be able to express a decoding net in some form of syntax.
The syntax presented in the paper adds two syntactical extensions to the plain
 decoding net that are focused on expressing real systems:
 First, the syntax works with ranges of addresses, because often whole 
address blocks are remapped. Second, the introduction of an overlay concept. 
If a node overlays another, it will map all addresses not otherwise mapped
to that node. We show that the syntax refines the decoding net.&lt;/p&gt;

&lt;p&gt;Based
on this syntax we have developed a system description language that
we use as a runtime representation of the memory system and at compile
time to generate initial kernel page tables.&lt;/p&gt;

&lt;p&gt;A further application is expressing real hardware with respect to the decoding
net. To showcase this, we model a simple software loaded translation lookaside
buffer (TLB) in Isabelle and map each of its configuration state to a model
node.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;The &lt;a href=&quot;https://link.springer.com/chapter/10.1007/978-3-319-94821-8_1&quot;&gt;paper&lt;/a&gt; presented in this blog post.&lt;/li&gt;
  &lt;li&gt;Our prior workshop &lt;a href=&quot;http://eptcs.web.cse.unsw.edu.au/paper.cgi?MARS2017.4&quot;&gt;paper&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;</content><author><name>Lukas Humbel (&lt;a href=&quot;http://people.inf.ethz.ch/humbell/&quot;&gt;home&lt;/a&gt;)</name></author><summary type="html">Modern memory systems are much more complicated than the traditionally assumed virtual and physical address space separation. We explain in this post which effects can not solely expressed by the basic model and are important for correct function of operating systems. We summarize our recent paper. In this work we present a theory for addressing in such modern memory subsystems. We formalize the theory in Isabelle/HOL.</summary></entry><entry><title type="html">A hammer you can only hold by the handle</title><link href="blog.systems.ethz.ch/blog/2018/a-hammer-you-can-only-hold-by-the-handle.html" rel="alternate" type="text/html" title="A hammer you can only hold by the handle" /><published>2018-11-05T00:00:00+00:00</published><updated>2018-11-05T00:00:00+00:00</updated><id>blog.systems.ethz.ch/blog/2018/a-hammer-you-can-only-hold-by-the-handle</id><content type="html" xml:base="blog.systems.ethz.ch/blog/2018/a-hammer-you-can-only-hold-by-the-handle.html">&lt;p&gt;Today we’re looking at the rust borrow checker from a different perspective. As you may know, the borrow checker is designed to safely handle memory allocation and ownership, preventing accessess to invalid memory and ensuring data-race freedom. This is a form of resource management: the borrow checker is tracking who’s in charge of a chunk of memory, and who is currently allowed to read or write to it. In this post, we’ll see how these facilities can be used to enforce higher-level API constraints in your libraries and software. Once you’re familiar with these techniques, we’ll cover how the same principles apply to advanced memory management and handling of other more abstract resources.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;This is an extended blog post version of my RustFest Zürich &lt;a href=&quot;http://zurich.rustfest.eu/sessions/andrea&quot;&gt;talk&lt;/a&gt; (it was &lt;a href=&quot;https://www.youtube.com/watch?v=3Q2hQfYW-XM&amp;amp;index=9&amp;amp;list=PL85XCvVPmGQj9mqbJizw-zi-EhcpS5jTP&quot;&gt;recorded&lt;/a&gt;). That’s why you’ll find “rustfest” in some of the code examples.&lt;/i&gt;&lt;/p&gt;

&lt;h2 id=&quot;affine-type-systems&quot;&gt;Affine type systems&lt;/h2&gt;

&lt;p&gt;First, a refresher on &lt;a href=&quot;https://en.wikipedia.org/wiki/Substructural_type_system&quot;&gt;&lt;em&gt;affine types&lt;/em&gt;&lt;/a&gt;. Affine type systems, like Rust’s, only allow a variable to be used once (if it’s not a reference). This is at the core of the ownership semantics, and it’s a significant departure from other mainstream languages (think of using a variable multiple times in C). Here’s an example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;use_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Andrea&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;use_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Note that &lt;code class=&quot;highlighter-rouge&quot;&gt;use_name&lt;/code&gt; takes &lt;code class=&quot;highlighter-rouge&quot;&gt;name&lt;/code&gt;’s ownership (and it’s not pass-by-reference) so &lt;code class=&quot;highlighter-rouge&quot;&gt;name&lt;/code&gt; is moved on line 5, and it cannot be used again on line 7. Here’s the compiler output:&lt;/p&gt;

&lt;pre class=&quot;highlight&quot;&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;error[E0382]&lt;/span&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;: use of moved value: `name`&lt;/span&gt;
 &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;--&amp;gt; &lt;/span&gt;affine.rs:7:18
  &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;|&lt;/span&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;5&lt;/span&gt; &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;| &lt;/span&gt;  use_name(name);
  &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;| &lt;/span&gt;           &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;----&lt;/span&gt; &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;value moved here&lt;/span&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;6&lt;/span&gt; &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;| &lt;/span&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;7&lt;/span&gt; &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;| &lt;/span&gt;  println!(&amp;quot;{}&amp;quot;, name);
  &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;| &lt;/span&gt;                 &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;^^^^&lt;/span&gt; &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;value used here after move&lt;/span&gt;
  &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;|&lt;/span&gt;
  &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;note&lt;/span&gt;: move occurs because `name` has type `std::string::String`,
          which does not implement the `Copy` trait

&lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;: aborting due to previous error&lt;/span&gt;

&lt;span style=&quot;font-weight:bold;&quot;&gt;For more information about this error, try `rustc --explain E0382`.&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;If you’d like a more in-depth explanation on &lt;em&gt;ownership&lt;/em&gt; (Rust’s lingo for its affine type system), you can take a look at the &lt;a href=&quot;https://doc.rust-lang.org/book/second-edition/ch04-01-what-is-ownership.html&quot;&gt;relevant chapter&lt;/a&gt; in the Rust book.&lt;/p&gt;

&lt;h2 id=&quot;drop&quot;&gt;Drop&lt;/h2&gt;

&lt;p&gt;Now we know what happens if we try to transfer ownership of a variable more than once, but what if we never use it inside a scope?&lt;/p&gt;

&lt;p&gt;First of all, Rust is lexically scoped, so variable names are only valid within the scope where they’re defined.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Thing&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;thing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Thing&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// `thing` dropped here&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;thing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;pre class=&quot;highlight&quot;&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;error[E0425]&lt;/span&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;: cannot find value `thing` in this scope&lt;/span&gt;
  &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;--&amp;gt; &lt;/span&gt;drop.rs:12:18
   &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;|&lt;/span&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;12&lt;/span&gt; &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;| &lt;/span&gt;  println!(&amp;quot;{}&amp;quot;, thing);
   &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;| &lt;/span&gt;                 &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;^^^^^&lt;/span&gt; &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;not found in this scope&lt;/span&gt;

&lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;: aborting due to previous error&lt;/span&gt;

&lt;span style=&quot;font-weight:bold;&quot;&gt;For more information about this error, try `rustc --explain E0425`.&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;No &lt;code class=&quot;highlighter-rouge&quot;&gt;thing&lt;/code&gt; there, it went out of scope on line 10. Importantly, &lt;code class=&quot;highlighter-rouge&quot;&gt;thing&lt;/code&gt; goes out of scope before its ownership is transfered, so Rust &lt;em&gt;drops&lt;/em&gt; it: the compiler inserts code to clean up all resources associated with &lt;code class=&quot;highlighter-rouge&quot;&gt;thing&lt;/code&gt; and frees its memory. We can hook into this mechanism by providing an implementation of the special &lt;code class=&quot;highlighter-rouge&quot;&gt;Drop&lt;/code&gt; trait:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Drop&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Thing&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;drop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nd&quot;&gt;eprintln!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;dropping thing {}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;thing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Thing&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
        &lt;span class=&quot;nd&quot;&gt;eprintln!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;inside scope&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// `thing` dropped here&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;eprintln!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;outside scope&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If we run this we get:&lt;/p&gt;

&lt;pre class=&quot;highlight&quot;&gt;
inside scope
dropping thing 4
outside scope
&lt;/pre&gt;

&lt;p&gt;Again, more details are in &lt;a href=&quot;https://doc.rust-lang.org/book/second-edition/ch15-03-drop.html&quot;&gt;the book&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;managing-resources&quot;&gt;Managing resources&lt;/h2&gt;

&lt;p&gt;We’re going to try to encode higher level API constraints using the &lt;em&gt;linear typing&lt;/em&gt; (&lt;em&gt;ownership&lt;/em&gt;) semantics of Rust.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/a-hammer-you-can-only-hold-by-the-handle/envelope-letter-lorry.svg&quot; alt=&quot;envelope, letter, lorry&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The interaction we’re going to describe is pretty simple: sending a letter via a delivery service. One has a written letter they’d like to send: they put it in a pre-stamped envelope, they close the envelope and they hand it to the lorry driver. Of course, all of this applies to many APIs: we’ll see a couple of examples at the end.&lt;/p&gt;

&lt;p&gt;Here’s one way to model our protocol in Rust:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;derive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Clone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Letter&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Envelope&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Option&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Letter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PickupLorryHandle&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// references to lorry's resources&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Letter&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Self&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Letter&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Envelope&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;/// Put a letter in the envelope and seal it.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;wrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.letter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;letter&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.clone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PickupLorryHandle&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;/// Give an envelope to the delivery driver.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;pickup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;envelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Envelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;// (the details here don't matter)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;/// Tell the driver we don't have anything else for them.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.done&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;sent&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;order_pickup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PickupLorryHandle&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;With this in place we can write our client code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c&quot;&gt;// in a separate module&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rustfest_letter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Dear RustFest&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rustfest_envelope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;buy_prestamped_envelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;rustfest_envelope&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.wrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rustfest_letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;order_pickup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.pickup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rustfest_envelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Our client code:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;writes a new letter (line 3),&lt;/li&gt;
  &lt;li&gt;buys a prestamped envelope (line 4),&lt;/li&gt;
  &lt;li&gt;puts the letter in the envelope and seals it (line 5),&lt;/li&gt;
  &lt;li&gt;orders a pickup from the delivery company (line 6),&lt;/li&gt;
  &lt;li&gt;hands the closed envelope to the driver (line 7),&lt;/li&gt;
  &lt;li&gt;tells the driver we don’t have anything else for them (line 8).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;1-2-3&quot;&gt;1, 2, 3&lt;/h2&gt;

&lt;p&gt;Our API has three shortcomings we can better address with Rust’s type system:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;we’d like to prevent re-use of what we know it’s a finite resource: we only have one physical copy of the letter;&lt;br /&gt;
&lt;img src=&quot;/assets/posts/a-hammer-you-can-only-hold-by-the-handle/letter-duplicate.svg&quot; alt=&quot;letter duplicate&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;we want to make sure that we perform a series of steps in the right order (and only once): put the letter in the envelope, seal it, and give it to the driver (i.e. avoid giving an empty envelope);&lt;br /&gt;
&lt;img src=&quot;/assets/posts/a-hammer-you-can-only-hold-by-the-handle/envelope-order.svg&quot; alt=&quot;letter, envelope, lorry&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;we don’t want to forget to release a resource when we’re done: we ensure we tell the driver they can leave.&lt;br /&gt;
&lt;img src=&quot;/assets/posts/a-hammer-you-can-only-hold-by-the-handle/lorry-questionmark.svg&quot; alt=&quot;lorry question&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;use-a-resource-only-once&quot;&gt;Use a resource only once&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/assets/posts/a-hammer-you-can-only-hold-by-the-handle/letter-duplicate.svg&quot; alt=&quot;letter duplicate&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Here’s some problematic client code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rustfest_letter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Dear RustFest&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;envelopes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;vec!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;buy_prestamped_envelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;buy_prestamped_envelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()];&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;order_pickup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;envelopes&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.iter_mut&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.wrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rustfest_letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.pickup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;No compiler error, but somehow the letter was magically duplicated and inserted in both envelopes. Sometimes, this is perfectly fine (copying some memory isn’t a big deal), but sometimes the resource represented by our &lt;code class=&quot;highlighter-rouge&quot;&gt;struct&lt;/code&gt; cannot be easily duplicated: in this example, if it’s representing a constraint in our business logic. In general, if our &lt;code class=&quot;highlighter-rouge&quot;&gt;struct&lt;/code&gt; represents a handle to a resource out of our control, we may not be able to &lt;code class=&quot;highlighter-rouge&quot;&gt;clone&lt;/code&gt; it without breaking some safety or correctness guarantees.&lt;/p&gt;

&lt;p&gt;So let’s remove the &lt;code class=&quot;highlighter-rouge&quot;&gt;Clone&lt;/code&gt; implementation for &lt;code class=&quot;highlighter-rouge&quot;&gt;Letter&lt;/code&gt;, and adjust the client code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot; id=&quot;figure-nonclone-letter&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;derive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Clone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Letter&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Envelope&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;wrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// take ownership of `letter`&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.letter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot; id=&quot;figure-nonclone-letter-main&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rustfest_letter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Dear RustFest&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;envelopes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;vec!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;buy_prestamped_envelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;buy_prestamped_envelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()];&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;order_pickup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;envelopes&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.iter_mut&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.wrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rustfest_letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// give ownership of `rustfest_letter`&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.pickup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;style type=&quot;text/css&quot;&gt;
#figure-nonclone-letter pre span:nth-child(-n+6) {
  background: rgba(255,230,0,0.5);
  text-decoration: line-through;
}

#figure-nonclone-letter pre span:nth-child(n+29):nth-child(-n+29) {
  background: rgba(255,230,0,0.5);
}

#figure-nonclone-letter-main pre span:nth-child(n+44):nth-child(-n+44) {
  background: rgba(255,230,0,0.5);
}

#figure-nonclone-letter-main pre span:nth-child(-n+33) {
  color: #aaa;
  font-weight: regular;
}

#figure-nonclone-letter-main pre span:nth-child(n+54) {
  color: #aaa;
  font-weight: regular;
}
&lt;/style&gt;

&lt;p&gt;Here’s the compiler output:&lt;/p&gt;

&lt;pre class=&quot;highlight&quot;&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;error[E0382]&lt;/span&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;: use of moved value: `rustfest_letter`&lt;/span&gt;
  &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;--&amp;gt; &lt;/span&gt;letter1.rs:7:16
   &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;|&lt;/span&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt; 7&lt;/span&gt; &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;| &lt;/span&gt;        e.wrap(rustfest_letter);
   &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;| &lt;/span&gt;               &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;^^^^^^^^^^^^^^^&lt;/span&gt; &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;value moved here in previous iteration of loop&lt;/span&gt;
   &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;|&lt;/span&gt;
   &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;note&lt;/span&gt;: move occurs because `rustfest_letter` has type `Letter`,
           which does not implement the `Copy` trait

&lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;: aborting due to previous error&lt;/span&gt;

&lt;span style=&quot;font-weight:bold;&quot;&gt;For more information about this error, try `rustc --explain E0382`.&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Great! We can now only use each letter once!&lt;/p&gt;

&lt;h2 id=&quot;enforce-order&quot;&gt;Enforce order&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/assets/posts/a-hammer-you-can-only-hold-by-the-handle/envelope-order.svg&quot; alt=&quot;letter duplicate&quot; /&gt;&lt;/p&gt;

&lt;p&gt;One issue down, two to go. We’d like to make sure that the steps of the protocol are carried out in the proper order: we must not forget to put the letter in the envelope before handing it to the lorry driver! And, can we prevent inserting two letters in the same envelope at compile time?&lt;/p&gt;

&lt;p&gt;Here’s the broken client code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot; id=&quot;figure-reuse-envelope&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rustfest_letter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Dear RustFest&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first_envelope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;buy_prestamped_envelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;first_envelope&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.wrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rustfest_letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eth_letter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Dear ETH&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;first_envelope&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.wrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eth_letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;order_pickup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.pickup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first_envelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;another_envelope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;buy_prestamped_envelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.pickup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;another_envelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;style type=&quot;text/css&quot;&gt;
#figure-reuse-envelope pre span:nth-child(n+24):nth-child(-n+24),
#figure-reuse-envelope pre span:nth-child(n+42):nth-child(-n+42),
#figure-reuse-envelope pre span:nth-child(n+68):nth-child(-n+68) {
  background: rgba(150,150,250,0.5);
}
&lt;/style&gt;

&lt;figure class=&quot;highlight&quot; id=&quot;figure-letter-assert&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Envelope&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;wrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.letter&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.is_none&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.letter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;letter&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.clone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;style type=&quot;text/css&quot;&gt;
#figure-letter-assert pre span:nth-child(n+18):nth-child(-n+24) {
  background: rgba(255,230,0,0.5);
}
&lt;/style&gt;

&lt;p&gt;This compiles, but of course the assert in &lt;code class=&quot;highlighter-rouge&quot;&gt;wrap&lt;/code&gt; will fire, at runtime.&lt;/p&gt;

&lt;pre class=&quot;highlight&quot;&gt;
thread 'main' panicked at 'assertion failed: self.letter.is_none()'
note: Run with `RUST_BACKTRACE=1` for a backtrace.
&lt;/pre&gt;

&lt;p&gt;We’d like to prevent this at compile time. And once that’s fixed, what about making sure we don’t send empty envelopes (&lt;code class=&quot;highlighter-rouge&quot;&gt;another_envelope&lt;/code&gt; on lines 12-13 of &lt;code class=&quot;highlighter-rouge&quot;&gt;main&lt;/code&gt;)?&lt;/p&gt;

&lt;p&gt;We can make a couple of classes to represent the current state of the &lt;code class=&quot;highlighter-rouge&quot;&gt;Envelope&lt;/code&gt;: &lt;code class=&quot;highlighter-rouge&quot;&gt;EmptyEnvelope&lt;/code&gt; is an empty pre-stampted envelope, and &lt;code class=&quot;highlighter-rouge&quot;&gt;ClosedEnvelope&lt;/code&gt; is a closed envelope guaranteed to contain a letter. We can then only provide implementations for actions that make sense for that specific state. Then, to make sure we don’t send an empty envelope, we make sure that &lt;code class=&quot;highlighter-rouge&quot;&gt;pickup&lt;/code&gt; only takes a &lt;code class=&quot;highlighter-rouge&quot;&gt;ClosedEnvelope&lt;/code&gt; (and we make it take ownership, to avoid spurious copies).&lt;/p&gt;

&lt;figure class=&quot;highlight&quot; id=&quot;figure-order-structs&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c&quot;&gt;/// An empty pre-stamped envelope.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EmptyEnvelope&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;/// A closed envelope containing a letter.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ClosedEnvelope&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EmptyEnvelope&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;/// Put a letter in the envelope and seal it.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;wrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ClosedEnvelope&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ClosedEnvelope&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;letter&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PickupLorryHandle&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;/// Give an envelope to the delivery driver.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;pickup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;envelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ClosedEnvelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;cm&quot;&gt;/* give letter */&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;buy_prestamped_envelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EmptyEnvelope&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EmptyEnvelope&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;style type=&quot;text/css&quot;&gt;
#figure-order-structs pre span:nth-child(n+56):nth-child(-n+56) {
  background: rgba(255,230,0,0.5);
}
&lt;/style&gt;

&lt;p&gt;And here’s the updated client code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot; id=&quot;figure-no-send-empty&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rustfest_letter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Dear RustFest&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first_envelope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;buy_prestamped_envelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;first_envelope&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.wrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rustfest_letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eth_letter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Dear ETH&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;first_envelope&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.wrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eth_letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;order_pickup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.pickup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first_envelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;another_envelope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;buy_prestamped_envelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.pickup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;another_envelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;style type=&quot;text/css&quot;&gt;
#figure-no-send-empty pre span:nth-child(n+56):nth-child(-n+56),
#figure-no-send-empty pre span:nth-child(n+66):nth-child(-n+66) {
  background: rgba(255,230,0,0.5);
}
#figure-no-send-empty pre span:nth-child(n+5):nth-child(-n+46),
#figure-no-send-empty pre span:nth-child(n+68):nth-child(-n+70) {
  color: #aaa;
  font-weight: regular;
}
&lt;/style&gt;

&lt;pre class=&quot;highlight&quot;&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;error[E0308]&lt;/span&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;: mismatched types&lt;/span&gt;
  &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;--&amp;gt; &lt;/span&gt;letter2.rs:10:18
   &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;|&lt;/span&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;10&lt;/span&gt; &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;| &lt;/span&gt;    lorry.pickup(first_envelope);
   &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;| &lt;/span&gt;                 &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;^^^^^^^^^^^^^^&lt;/span&gt; &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;expected struct `ClosedEnvelope`,
   &lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;| &lt;/span&gt;                                found struct `EmptyEnvelope`&lt;/span&gt;
   &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;|&lt;/span&gt;
   &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;note&lt;/span&gt;: expected type `&lt;span style=&quot;font-weight:bold;&quot;&gt;ClosedEnvelope&lt;/span&gt;`
              found type `&lt;span style=&quot;font-weight:bold;&quot;&gt;EmptyEnvelope&lt;/span&gt;`

&lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;error[E0308]&lt;/span&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;: mismatched types&lt;/span&gt;
  &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;--&amp;gt; &lt;/span&gt;letter2.rs:13:18
   &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;|&lt;/span&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;13&lt;/span&gt; &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;| &lt;/span&gt;    lorry.pickup(another_envelope);
   &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;| &lt;/span&gt;                 &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;^^^^^^^^^^^^^^^^&lt;/span&gt; &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;expected struct `ClosedEnvelope`,
   &lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;| &lt;/span&gt;                                     found struct `EmptyEnvelope`&lt;/span&gt;
   &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;|&lt;/span&gt;
   &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;note&lt;/span&gt;: expected type `&lt;span style=&quot;font-weight:bold;&quot;&gt;ClosedEnvelope&lt;/span&gt;`
              found type `&lt;span style=&quot;font-weight:bold;&quot;&gt;EmptyEnvelope&lt;/span&gt;`

&lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;: aborting due to 2 previous errors&lt;/span&gt;

&lt;span style=&quot;font-weight:bold;&quot;&gt;For more information about this error, try `rustc --explain E0308`.&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;One problem prevented: no empty envelopes can be sent! Note how the compiler errors point us towards a solution: we need a &lt;code class=&quot;highlighter-rouge&quot;&gt;ClosedEnvelope&lt;/code&gt; for the &lt;code class=&quot;highlighter-rouge&quot;&gt;lorry&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;pickup&lt;/code&gt;. Let’s fix the client code again.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot; id=&quot;figure-no-reuse-envelope&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rustfest_letter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Dear RustFest&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;envelope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;buy_prestamped_envelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;closed_envelope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;envelope&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.wrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rustfest_letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eth_letter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Dear ETH&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;closed_envelope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;envelope&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.wrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eth_letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;order_pickup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.pickup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;closed_envelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;style type=&quot;text/css&quot;&gt;
#figure-no-reuse-envelope pre span:nth-child(n+24):nth-child(-n+24),
#figure-no-reuse-envelope pre span:nth-child(n+45):nth-child(-n+45) {
  background: rgba(150,150,250,0.5);
}
#figure-no-reuse-envelope pre span:nth-child(n+63):nth-child(-n+65) {
  color: #aaa;
  font-weight: regular;
}
&lt;/style&gt;

&lt;pre class=&quot;highlight&quot;&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;error[E0382]&lt;/span&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;: use of moved value: `envelope`&lt;/span&gt;
  &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;--&amp;gt; &lt;/span&gt;letter2.rs:8:27
   &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;|&lt;/span&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt; 5&lt;/span&gt; &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;| &lt;/span&gt;    let closed_envelope = envelope.wrap(rustfest_letter);
   &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;| &lt;/span&gt;                          &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;--------&lt;/span&gt; &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;value moved here&lt;/span&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;...&lt;/span&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt; 8&lt;/span&gt; &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;| &lt;/span&gt;    let closed_envelope = envelope.wrap(eth_letter);
   &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;| &lt;/span&gt;                          &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;^^^^^^^^&lt;/span&gt; &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;value used here after move&lt;/span&gt;
   &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;|&lt;/span&gt;
   &lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;note&lt;/span&gt;: move occurs because `envelope` has type `EmptyEnvelope`,
           which does not implement the `Copy` trait

&lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:blue;font-weight:bold;text-decoration:blink;&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;: aborting due to previous error&lt;/span&gt;

&lt;span style=&quot;font-weight:bold;&quot;&gt;For more information about this error, try `rustc --explain E0382`.&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;By making &lt;code class=&quot;highlighter-rouge&quot;&gt;EmptyEnvelope&lt;/code&gt; take &lt;code class=&quot;highlighter-rouge&quot;&gt;self&lt;/code&gt;’s ownership we can use the &lt;em&gt;linear typing&lt;/em&gt; technique from earlier to prevent reuse of &lt;code class=&quot;highlighter-rouge&quot;&gt;envelope&lt;/code&gt;: once we’ve put a letter in an envelope, we get back a &lt;code class=&quot;highlighter-rouge&quot;&gt;ClosedEnvelope&lt;/code&gt;, that can only be handed over to the &lt;code class=&quot;highlighter-rouge&quot;&gt;lorry&lt;/code&gt; driver. Now the compiler can help us make sure we follow the protocol steps in order: put the letter in the envelope, then send it.&lt;/p&gt;

&lt;p&gt;We’ll see a more complex example in which we compose an http response in the right order using this technique. For now, here’s the correct client code with the new API:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rustfest_letter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Dear RustFest&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;envelope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;buy_prestamped_envelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;closed_envelope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;envelope&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.wrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rustfest_letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;order_pickup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.pickup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;closed_envelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;ensure-a-resource-is-released&quot;&gt;Ensure a resource is released&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/a-hammer-you-can-only-hold-by-the-handle/lorry-questionmark.svg&quot; alt=&quot;lorry question&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Another common mistake: forgetting to release a resource. In the following client code, &lt;code class=&quot;highlighter-rouge&quot;&gt;lorry.done()&lt;/code&gt; is missing, and we never tell the delivery driver we’re done. And, in this tortured methaphor, we’d never deliver the letter because the driver never leaves…&lt;/p&gt;

&lt;figure class=&quot;highlight&quot; id=&quot;figure-missing-done&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rustfest_letter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Dear RustFest&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;envelope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;buy_prestamped_envelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;closed_envelope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;envelope&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.wrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rustfest_letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;order_pickup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.pickup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;closed_envelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In the real world, we may be keeping a connection open, or never completing a process in our business logic; and it’s just because we forgot a single line.&lt;/p&gt;

&lt;p&gt;We’ve seen that we can hook into Rust’s &lt;em&gt;drop&lt;/em&gt; mechanism; here’s how we’d ensure that we release the &lt;code class=&quot;highlighter-rouge&quot;&gt;lorry&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Drop&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PickupLorryHandle&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;drop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.done&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PickupLorryHandle&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;/// Tell the driver we don't have anything else for them.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.done&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;sent&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot; id=&quot;figure-ensure-drop&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rustfest_letter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Dear RustFest&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;envelope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;buy_prestamped_envelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;closed_envelope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;envelope&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.wrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rustfest_letter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;order_pickup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lorry&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.pickup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;closed_envelope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;// `lorry` dropped here&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now when the lorry goes out of scope the &lt;code class=&quot;highlighter-rouge&quot;&gt;drop&lt;/code&gt; implementation is called, and we automatically send the driver on their merry way.&lt;/p&gt;

&lt;h2 id=&quot;in-the-std-library&quot;&gt;In the &lt;code class=&quot;highlighter-rouge&quot;&gt;std&lt;/code&gt; library&lt;/h2&gt;

&lt;p&gt;This last pattern is often used in the &lt;code class=&quot;highlighter-rouge&quot;&gt;std&lt;/code&gt; library when building abstractions where there’s a need to release a resource or a handle to a resource.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;Rc&lt;/code&gt;, “a single-threaded reference-counting pointer”, tracks the number of references to a resource, and the ownership of the &lt;code class=&quot;highlighter-rouge&quot;&gt;Rc&lt;/code&gt; pointer represents a strong reference: when no references are left (all &lt;code class=&quot;highlighter-rouge&quot;&gt;Rc&lt;/code&gt;s are dropped), the underlying resource (memory and other elements of the &lt;code class=&quot;highlighter-rouge&quot;&gt;struct&lt;/code&gt;) should be freed.&lt;/p&gt;

&lt;p&gt;There’s some &lt;code class=&quot;highlighter-rouge&quot;&gt;unsafe&lt;/code&gt; trickery under the hood, but what’s relevant here is that &lt;code class=&quot;highlighter-rouge&quot;&gt;Rc&lt;/code&gt; uses &lt;code class=&quot;highlighter-rouge&quot;&gt;Drop&lt;/code&gt; to release the underlying memory once the reference-count reaches zero.&lt;/p&gt;

&lt;p&gt;Here’s the relevant code: &lt;a href=&quot;https://doc.rust-lang.org/src/alloc/rc.rs.html#802-847&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;std::rc::Rc&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;k&quot;&gt;unsafe&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;may_dangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sized&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Drop&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Rc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// ...&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;drop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;unsafe&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.dec_strong&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.strong&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;c&quot;&gt;// destroy the contained object&lt;/span&gt;
                &lt;span class=&quot;nn&quot;&gt;ptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;drop_in_place&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.ptr&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.as_mut&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
                &lt;span class=&quot;c&quot;&gt;// ...&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Let’s look at another example in &lt;code class=&quot;highlighter-rouge&quot;&gt;std&lt;/code&gt;: &lt;code class=&quot;highlighter-rouge&quot;&gt;Mutex&lt;/code&gt;, “a mutual exclusion primitive useful for protecting shared data”.&lt;/p&gt;

&lt;p&gt;Locking a &lt;code class=&quot;highlighter-rouge&quot;&gt;Mutex&lt;/code&gt; returns a &lt;code class=&quot;highlighter-rouge&quot;&gt;MutexGuard&lt;/code&gt;, “an RAII implementation of a scoped lock of a mutex”, that is, an object that represents the fact that we’re holding the lock. And &lt;code class=&quot;highlighter-rouge&quot;&gt;Drop&lt;/code&gt; is used so we can release the lock just by &lt;code class=&quot;highlighter-rouge&quot;&gt;drop&lt;/code&gt;ping the guard (either explicitly, with &lt;a href=&quot;https://doc.rust-lang.org/std/mem/fn.drop.html&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;std::mem::drop&lt;/code&gt;&lt;/a&gt;, or when it goes out of scope).&lt;/p&gt;

&lt;p&gt;This is the signature of &lt;code class=&quot;highlighter-rouge&quot;&gt;Mutex::lock&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;pub fn lock(&amp;amp;self) -&amp;gt; LockResult&amp;lt;MutexGuard&amp;lt;T&amp;gt;&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And here’s the &lt;code class=&quot;highlighter-rouge&quot;&gt;Drop&lt;/code&gt; implementation for &lt;code class=&quot;highlighter-rouge&quot;&gt;MutexGuard&lt;/code&gt;:
&lt;a href=&quot;https://doc.rust-lang.org/src/std/sync/mutex.rs.html#452-460&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;std::sync::MutexGuard&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;stable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;feature&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;rust1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;since&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;1.0.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;'a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sized&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Drop&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MutexGuard&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;'a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;#[inline]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;drop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;unsafe&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.__lock.poison&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.__poison&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.__lock.inner&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.raw_unlock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;style type=&quot;text/css&quot;&gt;
#figure-ensure-drop pre span:nth-child(n+42):nth-child(-n+42) {
  display: inline-block;
  background: rgba(150,150,250,0.5);
  color: #666;
  padding: 4px 8px 4px 4px;
}
&lt;/style&gt;

&lt;h2 id=&quot;example-http-response&quot;&gt;Example: http response&lt;/h2&gt;

&lt;p&gt;Now let’s look at an example of how all of these techniques can be combined in a realistic API. Let’s say we’re building an http server library, and we want to make sure that when we write our response we first send all the headers, and only then start writing the body. We may also want to make sure not to forget to flush the buffer at the end.&lt;/p&gt;

&lt;p&gt;We use two structs to represent the two states: &lt;code class=&quot;highlighter-rouge&quot;&gt;HttpResponseWritingHeader&lt;/code&gt;, and &lt;code class=&quot;highlighter-rouge&quot;&gt;HttpResponseWritingBody&lt;/code&gt;. The method &lt;code class=&quot;highlighter-rouge&quot;&gt;body&lt;/code&gt; on &lt;code class=&quot;highlighter-rouge&quot;&gt;HttpResponseWritingHeader&lt;/code&gt; takes ownership of &lt;code class=&quot;highlighter-rouge&quot;&gt;self&lt;/code&gt;, ensuring that the header writer can no longer be used after this call (its ownership is transfered), and we can only append additional chunks to the response body.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HttpResponseWritingHeaders&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* connection, … */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HttpResponseWritingBody&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* ... */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;start_response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HttpResponseWritingHeaders&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* ... */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HttpResponseWritingHeaders&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* ... */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HttpResponseWritingBody&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* ... */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HttpResponseWritingBody&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;chunk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Chunk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* ... */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;cease&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Drop&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HttpResponseWritingBody&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;drop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.flush&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;Drop&lt;/code&gt; implementation ensures that a completed response is always fully written out to the client.&lt;/p&gt;

&lt;h2 id=&quot;state-explosion&quot;&gt;State explosion&lt;/h2&gt;

&lt;p&gt;Note that the technique of representing the state of a protocol/object with many structs has a significant drawback when the possible state space grows large: we may end up juggling a lot of structs, and the benefit of compile time checks may not be worth the cost in lines-of-code, and maintainability.&lt;/p&gt;

&lt;h2 id=&quot;example-streaming-engine&quot;&gt;Example: streaming engine&lt;/h2&gt;

&lt;p&gt;At the &lt;a href=&quot;https://www.systems.ethz.ch&quot;&gt;Systems Group&lt;/a&gt; of the &lt;a href=&quot;https://www.inf.ethz.ch&quot;&gt;ETH Zürich CS department&lt;/a&gt;, we’re working on &lt;a href=&quot;https://github.com/frankmcsherry/timely-dataflow&quot;&gt;timely dataflow&lt;/a&gt;, a low-latency cyclic dataflow computational model: it lets you describe computations as a cyclic graph of nodes (operators), that perform some transformation on incoming data and maintain local state, and edges (channels) that carry data between operators. A computation built this way can be automatically parallelised across cores and computers, over the network.&lt;/p&gt;

&lt;p&gt;In timely dataflow, data is transported on channels as tuples, each carrying a logical timestamp.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/a-hammer-you-can-only-hold-by-the-handle/lorry-time.svg&quot; alt=&quot;lorry-time&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Timestamps are used to represent logical boundaries between groups of tuples so that operations can be performed on some subset, and timely dataflow tracks which timestamps are in flight in the system. Importantly, for timely dataflow’s correctness, operators are only allowed to send messages with timestamp &lt;code class=&quot;highlighter-rouge&quot;&gt;t&lt;/code&gt; when they hold a &lt;code class=&quot;highlighter-rouge&quot;&gt;Capability&lt;/code&gt; for the same timestamp &lt;code class=&quot;highlighter-rouge&quot;&gt;t&lt;/code&gt;. In addition, they need to report whenever they relinquish one of these capabilities, so that the system can make forward progress (that is, a downstream operator can then process all the tuples associated with the capability’s timestamp).&lt;/p&gt;

&lt;p&gt;In timely, we use something like the following to represent a &lt;code class=&quot;highlighter-rouge&quot;&gt;Capability&lt;/code&gt;, a resource which grants permission to send data at a certain timestamp.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c&quot;&gt;/// The capability to send data with a certain timestamp on a dataflow edge.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Capability&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Timestamp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;internal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Rc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RefCell&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ChangeBatch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Timestamp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Clone&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Capability&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;clone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Capability&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;// … update self.internal …&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Timestamp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Drop&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Capability&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;drop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;// … update self.internal …&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;/// Return a channel handle to send data at the timestamp carried by `cap`.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Capability&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Handle&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;Capability&lt;/code&gt; has a custom &lt;code class=&quot;highlighter-rouge&quot;&gt;Clone&lt;/code&gt; implementation, that keeps track of how many copies we’ve made (a bit like &lt;code class=&quot;highlighter-rouge&quot;&gt;Rc&lt;/code&gt;), and a &lt;code class=&quot;highlighter-rouge&quot;&gt;Drop&lt;/code&gt; implementation, so we can be sure that a &lt;code class=&quot;highlighter-rouge&quot;&gt;Capability&lt;/code&gt; is dropped if not explicitly retained. The function that an operator uses to write to its output requires a reference to a valid &lt;code class=&quot;highlighter-rouge&quot;&gt;Capability&lt;/code&gt; for a certain timestamp: this way we enforce, at compile time, one of the protocol constraints of timely dataflow.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Thanks for reading! You can send me notes and questions &lt;a href=&quot;https://twitter.com/utaal&quot;&gt;on twitter&lt;/a&gt;. There’s a &lt;a href=&quot;https://lobste.rs/s/5nmyze/hammer_you_can_only_hold_by_handle&quot;&gt;lobste.rs&lt;/a&gt; and a &lt;a href=&quot;https://www.reddit.com/r/rust/comments/9uccla/a_hammer_you_can_only_hold_by_the_handle/&quot;&gt;reddit&lt;/a&gt; post for comments.&lt;/i&gt;&lt;/p&gt;</content><author><name>Andrea Lattuada (&lt;a href=&quot;https://twitter.com/utaal&quot;&gt;@utaal&lt;/a&gt;)</name></author><summary type="html">Today we’re looking at the rust borrow checker from a different perspective. As you may know, the borrow checker is designed to safely handle memory allocation and ownership, preventing accessess to invalid memory and ensuring data-race freedom. This is a form of resource management: the borrow checker is tracking who’s in charge of a chunk of memory, and who is currently allowed to read or write to it. In this post, we’ll see how these facilities can be used to enforce higher-level API constraints in your libraries and software. Once you’re familiar with these techniques, we’ll cover how the same principles apply to advanced memory management and handling of other more abstract resources.</summary></entry></feed>