Jekyll2018-03-19T13:19:22+01:00https://paul.lietar.net/Tales of a Wanna-be Computer ScientistPaul LiétarHow to train your Pony: Introduction2018-03-19T00:00:00+01:002018-03-19T00:00:00+01:00https://paul.lietar.net/2018/03/how-to-train-your-pony-introduction<p><em>This article is the first in a series of blog posts about the Pony language’s type system, with a
focus on the capability system.</em></p>
<h2 id="pony">Pony</h2>
<p>Pony is a programming language which aims at making it easier to write
concurrent programs. Among other things, the language promises that any program
which successfully compiles cannot experience data races. The goal of this
series of blog posts is to explore how it achieves this, by designing our own
miniature version of the language and “training” it until it becomes (almost) as
powerful as the full Pony language.</p>
<p>In these posts I’ll assume some familiarity with Pony. If you are new to it, I
recommend you check out the <a href="https://tutorial.ponylang.org/">tutorial from the Pony website</a> first.</p>
<h2 id="data-races">Data races</h2>
<p>Data-races happen when two actors access the same object concurrently, and at
least one of them is modifying it. The behaviour when a data race occurs is
undefined, and can lead to all sorts of corruption.</p>
<p>If you are not familiar with actors just think of them as threads. There are
some interesting differences between the two, but for the purpose of these blog
posts it doesn’t matter.</p>
<p>Consider the simple example below. If two actors try to call the <code class="highlighter-rouge">increment</code>
method on the same <code class="highlighter-rouge">Counter</code> object at the same time, it is possible that both
actors read the old value, both perform the addition on that value and both
write back the same result. Overall the counter would have been incremented by
one, even though the method was called twice.</p>
<div class="language-pony highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">class</span> <span class="nc">Counter</span>
<span class="kr">var</span> <span class="n">value</span><span class="o">:</span> <span class="nc">U64</span> <span class="o">=</span> <span class="mi">0</span>
<span class="kr">fun</span> <span class="kd">ref</span> <span class="n">increment</span><span class="p">()</span> <span class="o">=></span>
<span class="n">value</span> <span class="o">=</span> <span class="n">value</span> <span class="o">+</span> <span class="mi">1</span>
</code></pre></div></div>
<p>Actually, things could be even worse than simply incrementing once instead of
twice. Under the C memory model, which Pony shares, the behaviour is undefined
and the resulting value could be the old one, the old value incremented once,
the old value incremented twice or completely garbage. It could even have side
effects beyond that object’s value.</p>
<p>Note that atomic operations allow safe concurrent modifications, but I won’t
consider these here.</p>
<h2 id="preventing-data-races">Preventing data races</h2>
<p>In languages like C or Java, it is up to the programmer to make sure data races
cannot happen, by carefully protecting accesses to shared data. In large
programs, this can be a very challenging tasks and it is easy to forget about it
and make mistakes. Data-races are inherently unpredictable and often hard to
reproduce, making it an ever harder task to debug.</p>
<p>A trend in recent languages, such as Pony and Rust, is to have the compiler
detect risks of data races statically and throw a compile-time error. Thanks to
this you are guaranteed that a program which compiles cannot experience any data
race at run-time.</p>
<p>However, catching data races at compile time has a big impact on the design of
the language. This series of blog posts is going to cover how do we go from our
goal of “programs which compile cannot cause data races” to the design of Pony’s
reference capabilities.</p>
<p>We’ll start with a small set of very restrictive rules, and slowly build up on
them until we reach Pony’s rules. Along the way we’ll prove that these rules
indeed give us the guarantee that we are looking for, at first informally and
maybe later touch a bit on the formal and computer verified proofs.</p>
<p>There’s quite a lot to do there, so let’s get started!</p>
<h2 id="my-little-pony">My Little Pony</h2>
<p>Before we even start thinking about data races we should agree on what
programming language we’re talking about, and what its semantics are.</p>
<p>The Pony language as implemented by the compiler is quite complicated for our
purpose, with most features being irrelevant to what we want to achieve here.
Instead we’ll be using our own very minimal version of it, <em>Little Pony</em>.</p>
<figure>
<img src="https://paul.lietar.net/assets/train-your-pony/2018-03-15-introduction/hello.gif" />
<figcaption>The best thing about the Pony language is definitely the infinite number of available GIFs.</figcaption>
</figure>
<p>Our initial version of <em>Little Pony</em> is going to be very simple. The language
only has one object type, <code class="highlighter-rouge">Counter</code> with builtin methods <code class="highlighter-rouge">increment</code>,
<code class="highlighter-rouge">decrement</code> and <code class="highlighter-rouge">is_zero</code> which work as you’d expect. Additionally it supports
booleans and simple control flow structures, such as <code class="highlighter-rouge">if</code>/<code class="highlighter-rouge">else</code> and <code class="highlighter-rouge">while</code>
blocks.</p>
<div class="language-pony highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">var</span> <span class="n">x</span> <span class="o">=</span> <span class="nc">Counter</span><span class="p">()</span> <span class="c1">// Create a new counter object, assign it to variable `x`
</span><span class="n">x</span><span class="p">.</span><span class="n">increment</span><span class="p">()</span>
<span class="kr">if</span> <span class="n">x</span><span class="p">.</span><span class="n">is_zero</span><span class="p">()</span> <span class="kr">then</span>
<span class="n">x</span><span class="p">.</span><span class="n">increment</span><span class="p">()</span>
<span class="kr">end</span>
</code></pre></div></div>
<p>The language supports aliasing. When making an assignment such as <code class="highlighter-rouge">y = x</code>, the
object pointed at by <code class="highlighter-rouge">x</code> is not copied, only the reference to it is. The
variable <code class="highlighter-rouge">y</code> starts pointing at the same object.</p>
<div class="language-pony highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">var</span> <span class="n">x</span> <span class="o">=</span> <span class="nc">Counter</span><span class="p">()</span>
<span class="kr">var</span> <span class="n">y</span> <span class="o">=</span> <span class="n">x</span>
<span class="n">y</span><span class="p">.</span><span class="n">increment</span><span class="p">()</span>
<span class="c1">// This is false, x and y point to the same object,
// which was incremented just before.
</span><span class="n">x</span><span class="p">.</span><span class="n">is_zero</span><span class="p">()</span>
</code></pre></div></div>
<p>Finally, our language supports user-defined actors with a number of behaviours
which get executed when a message is received. However unlike in the full Pony
language, there is exactly one instance per defined actor type. Messages can
therefore be sent to actors by simply mentioning the actor’s type and the
behaviour’s name, and optionally some arguments. For example, <code class="highlighter-rouge">Foo.bar(x)</code> sends
a <code class="highlighter-rouge">bar</code> message to the actor of type <code class="highlighter-rouge">Foo</code> with <code class="highlighter-rouge">x</code> as an argument.</p>
<div class="language-pony highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Reset as a service
</span><span class="kr">actor</span> <span class="nc">Reset</span>
<span class="kr">be</span> <span class="n">reset</span><span class="p">(</span><span class="n">x</span><span class="o">:</span> <span class="nc">Counter</span><span class="p">)</span> <span class="o">=></span>
<span class="c1">// Keep decrementing the counter until it reaches zero
</span> <span class="kr">while</span> <span class="kr">not</span> <span class="n">x</span><span class="p">.</span><span class="n">is_zero</span><span class="p">()</span>
<span class="kr">then</span> <span class="n">x</span><span class="p">.</span><span class="n">decrement</span><span class="p">()</span>
<span class="kr">end</span>
<span class="kr">actor</span> <span class="nc">Main</span>
<span class="c1">// Program starts here
</span> <span class="kr">be</span> <span class="n">main</span><span class="p">()</span> <span class="o">=></span>
<span class="kr">var</span> <span class="n">x</span> <span class="o">=</span> <span class="nc">Counter</span><span class="p">()</span>
<span class="n">x</span><span class="p">.</span><span class="n">increment</span><span class="p">()</span>
<span class="nc">Reset</span><span class="p">.</span><span class="n">reset</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="c1">// Send a message to the `Reset` actor
</span></code></pre></div></div>
<p>Note that messages are sent asynchronously. In the program above, after sending
the <code class="highlighter-rouge">reset</code> message, the <code class="highlighter-rouge">main</code> behaviour keeps executing without waiting for a
response. Since actors are executed concurrently, <code class="highlighter-rouge">reset</code> may start executing
before <code class="highlighter-rouge">main</code> has completed.</p>
<p>In the program below, I’ve added a second <code class="highlighter-rouge">increment</code> call in <code class="highlighter-rouge">main</code>. This call
could execute while <code class="highlighter-rouge">Reset</code> is accessing the same counter object, causing a data
race.</p>
<div class="language-pony highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">actor</span> <span class="nc">Main</span>
<span class="kr">be</span> <span class="n">main</span><span class="p">()</span> <span class="o">=></span>
<span class="kr">var</span> <span class="n">x</span> <span class="o">=</span> <span class="nc">Counter</span><span class="p">()</span>
<span class="n">x</span><span class="p">.</span><span class="n">increment</span><span class="p">()</span>
<span class="nc">Reset</span><span class="p">.</span><span class="n">reset</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
<span class="n">x</span><span class="p">.</span><span class="n">increment</span><span class="p">()</span> <span class="c1">// Data race here !
</span></code></pre></div></div>
<p>Of course we could have been more careful when writing the program and avoid
this problem, but this places a heavy burden on the programmer. Instead our goal
will be to define some rules that programs must follow and which can be checked
statically by a compiler. These rules will guarantee that the program is free of
data races.</p>
<figure>
<img src="https://paul.lietar.net/assets/train-your-pony/2018-03-15-introduction/scared1.gif" />
<figcaption>A data race!</figcaption>
</figure>
<h2 id="well-formed-heaps">Well-formed heaps</h2>
<p>The first step in making our language free of data races is define a property
about a program’s runtime state. The runtime state is called the heap, and the
property about it well-formedness.</p>
<p>We want to choose a definition of well-formedness such that at <em>a given point in
time</em>, if the heap is well-formed then no data race can happen. We will later
extend this to all points in time, implying that a data race can <em>never</em> happen.</p>
<h3 id="examples">Examples</h3>
<p>So how do we decide if a heap is well-formed or not? Well let’s start by looking
at two examples, one heap where a data-race might happen and one where they
can’t. I use diagrams to help describe the actors and objects present in a
heap, using arrows from actors to objects to represent variables.</p>
<figure class="bad-heap">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="244pt" height="116pt" viewBox="0.00 0.00 244.26 116.00">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 112)">
<title>%3</title>
<g id="node1" class="node"><title>A1</title>
<polygon fill="none" stroke="black" points="-0.129664,-84.4377 54.6294,-72 109.388,-84.4377 109.337,-104.562 -0.0785533,-104.562 -0.129664,-84.4377"></polygon>
<text text-anchor="middle" x="54.6294" y="-86.3" font-family="menlo" font-size="14.00">Actor 1</text>
</g>
<g id="node3" class="node"><title>object</title>
<polygon fill="none" stroke="black" points="148.629,-36 86.6294,-36 86.6294,-0 148.629,-0 148.629,-36"></polygon>
<text text-anchor="middle" x="117.629" y="-14.3" font-family="menlo" font-size="14.00">Object</text>
</g>
<g id="edge1" class="edge"><title>A1->object</title>
<path fill="none" stroke="black" d="M67.3783,-74.8345C75.4007,-65.9207 85.9743,-54.1723 95.3519,-43.7527"></path>
<polygon fill="black" stroke="black" points="98.1398,-45.8871 102.228,-36.1127 92.9367,-41.2043 98.1398,-45.8871"></polygon>
</g>
<g id="node2" class="node"><title>A2</title>
<polygon fill="none" stroke="black" points="126.87,-84.4377 181.629,-72 236.388,-84.4377 236.337,-104.562 126.921,-104.562 126.87,-84.4377"></polygon>
<text text-anchor="middle" x="181.629" y="-86.3" font-family="menlo" font-size="14.00">Actor 2</text>
</g>
<g id="edge2" class="edge"><title>A2->object</title>
<path fill="none" stroke="black" d="M168.678,-74.8345C160.528,-65.9207 149.787,-54.1723 140.26,-43.7527"></path>
<polygon fill="black" stroke="black" points="142.606,-41.1313 133.275,-36.1127 137.44,-45.8547 142.606,-41.1313"></polygon>
</g>
</g>
</svg>
<figcaption>Red heaps are bad.</figcaption>
</figure>
<p>This first example is the kind of heap we want to prevent. Both actors have
access to the same object, which could cause a data race if they both start
accessing it simultaneously.</p>
<figure class="good-heap">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="244pt" height="131pt" viewBox="0.00 0.00 244.26 131.00">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 127)">
<title>%3</title>
<g id="node1" class="node"><title>A1</title>
<polygon fill="none" stroke="black" points="-0.129664,-99.4377 54.6294,-87 109.388,-99.4377 109.337,-119.562 -0.0785533,-119.562 -0.129664,-99.4377"></polygon>
<text text-anchor="middle" x="54.6294" y="-101.3" font-family="menlo" font-size="14.00">Actor 1</text>
</g>
<g id="node3" class="node"><title>O1</title>
<polygon fill="none" stroke="black" points="92.6294,-36 16.6294,-36 16.6294,-0 92.6294,-0 92.6294,-36"></polygon>
<text text-anchor="middle" x="54.6294" y="-14.3" font-family="menlo" font-size="14.00">Object 1</text>
</g>
<g id="edge1" class="edge"><title>A1:sw->O1</title>
<path fill="none" stroke="black" d="M39.6294,-89C28.3109,-77.6815 32.177,-60.0349 38.8142,-45.2918"></path>
<polygon fill="black" stroke="black" points="42.0628,-46.623 43.4441,-36.1186 35.8137,-43.4688 42.0628,-46.623"></polygon>
<text text-anchor="middle" x="40.1294" y="-57.8" font-family="menlo" font-size="14.00">x</text>
</g>
<g id="edge2" class="edge"><title>A1:se->O1</title>
<path fill="none" stroke="black" d="M69.6294,-89C80.9478,-77.6815 77.0817,-60.0349 70.4445,-45.2918"></path>
<polygon fill="black" stroke="black" points="73.445,-43.4688 65.8146,-36.1186 67.1959,-46.623 73.445,-43.4688"></polygon>
<text text-anchor="middle" x="82.1294" y="-57.8" font-family="menlo" font-size="14.00">y</text>
</g>
<g id="node2" class="node"><title>A2</title>
<polygon fill="none" stroke="black" points="126.87,-99.4377 181.629,-87 236.388,-99.4377 236.337,-119.562 126.921,-119.562 126.87,-99.4377"></polygon>
<text text-anchor="middle" x="181.629" y="-101.3" font-family="menlo" font-size="14.00">Actor 2</text>
</g>
<g id="node4" class="node"><title>O2</title>
<polygon fill="none" stroke="black" points="219.629,-36 143.629,-36 143.629,-0 219.629,-0 219.629,-36"></polygon>
<text text-anchor="middle" x="181.629" y="-14.3" font-family="menlo" font-size="14.00">Object 2</text>
</g>
<g id="edge3" class="edge"><title>A2->O2</title>
<path fill="none" stroke="black" d="M181.629,-86.799C181.629,-75.1626 181.629,-59.5479 181.629,-46.2368"></path>
<polygon fill="black" stroke="black" points="185.129,-46.1754 181.629,-36.1754 178.129,-46.1755 185.129,-46.1754"></polygon>
</g>
</g>
</svg>
<figcaption>Green heaps are good.</figcaption>
</figure>
<p>This second heap however is perfectly fine. The two actors have access to a
distinct set of objects. Even though <code class="highlighter-rouge">Actor 1</code> can access <code class="highlighter-rouge">Object 1</code> through two
different variables, there’s no risk of data race as it can only use one of
these at a time.</p>
<h3 id="notation-and-definition">Notation and Definition</h3>
<p>From these examples we can draw our first definition of well-formedness, but
first let’s introduce a few notations. We’ll use the letters <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>χ</mi></mrow><annotation encoding="application/x-tex">\chi</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:0.43056em;"></span><span class="strut bottom" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="base"><span class="mord mathit">χ</span></span></span></span> (chi) to
represent a heap, <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>α</mi></mrow><annotation encoding="application/x-tex">\alpha</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:0.43056em;"></span><span class="strut bottom" style="height:0.43056em;vertical-align:0em;"></span><span class="base"><span class="mord mathit" style="margin-right:0.0037em;">α</span></span></span></span> (alpha) for actors and <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>ι</mi></mrow><annotation encoding="application/x-tex">\iota</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:0.43056em;"></span><span class="strut bottom" style="height:0.43056em;vertical-align:0em;"></span><span class="base"><span class="mord mathit">ι</span></span></span></span> (iota) for objects.
Finally we use <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>χ</mi><mo separator="true">,</mo><mi>α</mi><mo>⊢</mo><mi>ι</mi></mrow><annotation encoding="application/x-tex">\chi, \alpha \vdash \iota</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:0.69444em;"></span><span class="strut bottom" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="base"><span class="mord mathit">χ</span><span class="mpunct">,</span><span class="mord rule" style="margin-right:0.16666666666666666em;"></span><span class="mord mathit" style="margin-right:0.0037em;">α</span><span class="mord rule" style="margin-right:0.2777777777777778em;"></span><span class="mrel">⊢</span><span class="mord rule" style="margin-right:0.2777777777777778em;"></span><span class="mord mathit">ι</span></span></span></span> to denote that in heap <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>χ</mi></mrow><annotation encoding="application/x-tex">\chi</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:0.43056em;"></span><span class="strut bottom" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="base"><span class="mord mathit">χ</span></span></span></span>,
the actor <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>α</mi></mrow><annotation encoding="application/x-tex">\alpha</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:0.43056em;"></span><span class="strut bottom" style="height:0.43056em;vertical-align:0em;"></span><span class="base"><span class="mord mathit" style="margin-right:0.0037em;">α</span></span></span></span> has access to object <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>ι</mi></mrow><annotation encoding="application/x-tex">\iota</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:0.43056em;"></span><span class="strut bottom" style="height:0.43056em;vertical-align:0em;"></span><span class="base"><span class="mord mathit">ι</span></span></span></span>.</p>
<p>Using these notations, the definition of well-formedness we’ll use is the
following:</p>
<p><em>A heap <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>χ</mi></mrow><annotation encoding="application/x-tex">\chi</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:0.43056em;"></span><span class="strut bottom" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="base"><span class="mord mathit">χ</span></span></span></span> is well formed if and only if for all actors <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>α</mi><mn>1</mn></msub></mrow><annotation encoding="application/x-tex">\alpha_1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:0.43056em;"></span><span class="strut bottom" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="base"><span class="mord"><span class="mord mathit" style="margin-right:0.0037em;">α</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.0037em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"></span></span></span></span></span></span></span></span> and
<span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>α</mi><mn>2</mn></msub></mrow><annotation encoding="application/x-tex">\alpha_2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:0.43056em;"></span><span class="strut bottom" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="base"><span class="mord"><span class="mord mathit" style="margin-right:0.0037em;">α</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.0037em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"></span></span></span></span></span></span></span></span> in <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>χ</mi></mrow><annotation encoding="application/x-tex">\chi</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:0.43056em;"></span><span class="strut bottom" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="base"><span class="mord mathit">χ</span></span></span></span> such that <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>α</mi><mn>1</mn></msub><mo>≠</mo><msub><mi>α</mi><mn>2</mn></msub></mrow><annotation encoding="application/x-tex">\alpha_1 \neq \alpha_2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:0.716em;"></span><span class="strut bottom" style="height:0.9309999999999999em;vertical-align:-0.215em;"></span><span class="base"><span class="mord"><span class="mord mathit" style="margin-right:0.0037em;">α</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.0037em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"></span></span></span></span></span><span class="mord rule" style="margin-right:0.2777777777777778em;"></span><span class="mrel">≠</span><span class="mord rule" style="margin-right:0.2777777777777778em;"></span><span class="mord"><span class="mord mathit" style="margin-right:0.0037em;">α</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.0037em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"></span></span></span></span></span></span></span></span>, there does not
exist an object <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>ι</mi></mrow><annotation encoding="application/x-tex">\iota</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:0.43056em;"></span><span class="strut bottom" style="height:0.43056em;vertical-align:0em;"></span><span class="base"><span class="mord mathit">ι</span></span></span></span> such that <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>χ</mi><mo separator="true">,</mo><msub><mi>α</mi><mn>1</mn></msub><mo>⊢</mo><mi>ι</mi></mrow><annotation encoding="application/x-tex">\chi, \alpha_1 \vdash \iota</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:0.69444em;"></span><span class="strut bottom" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="base"><span class="mord mathit">χ</span><span class="mpunct">,</span><span class="mord rule" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mord mathit" style="margin-right:0.0037em;">α</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.0037em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"></span></span></span></span></span><span class="mord rule" style="margin-right:0.2777777777777778em;"></span><span class="mrel">⊢</span><span class="mord rule" style="margin-right:0.2777777777777778em;"></span><span class="mord mathit">ι</span></span></span></span> and
<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>χ</mi><mo separator="true">,</mo><msub><mi>α</mi><mn>2</mn></msub><mo>⊢</mo><mi>ι</mi></mrow><annotation encoding="application/x-tex">\chi, \alpha_2 \vdash \iota</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:0.69444em;"></span><span class="strut bottom" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="base"><span class="mord mathit">χ</span><span class="mpunct">,</span><span class="mord rule" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mord mathit" style="margin-right:0.0037em;">α</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.0037em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"></span></span></span></span></span><span class="mord rule" style="margin-right:0.2777777777777778em;"></span><span class="mrel">⊢</span><span class="mord rule" style="margin-right:0.2777777777777778em;"></span><span class="mord mathit">ι</span></span></span></span>.</em></p>
<p>You can see how this achieves our goal of preventing data-races. If no object is
accessible from two different actors, then there is nothing to worry about.</p>
<h2 id="preservation-of-well-formedness">Preservation of Well-Formedness</h2>
<p>We’ve now etablished what it means for a heap to be well-formed, and we can see
that with a well-formed heap no data race can happen. However we still have to
show that our heaps actually are well-formed.</p>
<p>For this, we show that our initial heap, when the program starts, is well-formed
and that every execution step after that preserves its well-formedness. Our
program starts with a number of actors but no objects, which makes the initial
heap trivially well-formed.</p>
<p>The second part, proving preservation, requires more work. We need to consider
every possible execution step and look at how it modifies the heap.</p>
<h3 id="uninteresting-cases">Uninteresting cases</h3>
<p>There are a few operations in our language which do not affect the shape of our
heaps. For example reading a counter’s value and control flow operations <code class="highlighter-rouge">if</code>
and <code class="highlighter-rouge">while</code> don’t modify the heap at all, so they obviously preserve its
well-formedness.</p>
<p>Modifying <code class="highlighter-rouge">Counter</code> objects using the <code class="highlighter-rouge">increment</code> or <code class="highlighter-rouge">decrement</code> method modifies
the heap by changing the counter’s value, but the heap’s shape itself is
untouched. No actor starts seeing a new object it didn’t see before, and
well-formedness is preserved.</p>
<h3 id="object-creation">Object creation</h3>
<div class="language-pony highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">var</span> <span class="n">x</span> <span class="o">=</span> <span class="nc">Counter</span><span class="p">()</span>
</code></pre></div></div>
<p>When an actor creates an object, it starts having access to it. However, as this
object is brand new, no other actor can have access to it yet. Since all other
objects are untouched, well-formedness is preserved.</p>
<figure class="good-heap">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="95pt" height="131pt" viewBox="0.00 0.00 94.76 131.00">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 127)">
<title>%3</title>
<g id="node1" class="node"><title>A</title>
<polygon fill="none" stroke="black" points="0.117544,-99.4377 43.3821,-87 86.6467,-99.4377 86.6063,-119.562 0.157926,-119.562 0.117544,-99.4377"></polygon>
<text text-anchor="middle" x="43.3821" y="-101.3" font-family="menlo" font-size="14.00">Actor</text>
</g>
<g id="node2" class="node"><title>object</title>
<polygon fill="none" stroke="black" points="74.3821,-36 12.3821,-36 12.3821,-0 74.3821,-0 74.3821,-36"></polygon>
<text text-anchor="middle" x="43.3821" y="-14.3" font-family="menlo" font-size="14.00">Object</text>
</g>
<g id="edge1" class="edge"><title>A->object</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M43.3821,-86.799C43.3821,-75.1626 43.3821,-59.5479 43.3821,-46.2368"></path>
<polygon fill="black" stroke="black" points="46.8822,-46.1754 43.3821,-36.1754 39.8822,-46.1755 46.8822,-46.1754"></polygon>
<text text-anchor="middle" x="47.8821" y="-57.8" font-family="menlo" font-size="14.00">x</text>
</g>
</g>
</svg>
<figcaption>The dashed line represents a newly created reference.</figcaption>
</figure>
<h3 id="aliasing">Aliasing</h3>
<div class="language-pony highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// x points to an object
</span><span class="kr">var</span> <span class="n">y</span> <span class="o">=</span> <span class="n">x</span>
</code></pre></div></div>
<p>By aliasing a reference, we create a new one that points to the same object.
This is allowed by our definition of well-formed heaps, since both references
come from the same actor.</p>
<figure class="good-heap">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="95pt" height="131pt" viewBox="0.00 0.00 94.76 131.00">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 127)">
<title>%3</title>
<g id="node1" class="node"><title>A</title>
<polygon fill="none" stroke="black" points="0.117544,-99.4377 43.3821,-87 86.6467,-99.4377 86.6063,-119.562 0.157926,-119.562 0.117544,-99.4377"></polygon>
<text text-anchor="middle" x="43.3821" y="-101.3" font-family="menlo" font-size="14.00">Actor</text>
</g>
<g id="node2" class="node"><title>O</title>
<polygon fill="none" stroke="black" points="74.3821,-36 12.3821,-36 12.3821,-0 74.3821,-0 74.3821,-36"></polygon>
<text text-anchor="middle" x="43.3821" y="-14.3" font-family="menlo" font-size="14.00">Object</text>
</g>
<g id="edge1" class="edge"><title>A:sw->O</title>
<path fill="none" stroke="black" d="M29.3821,-90C17.8678,-78.4856 21.6011,-60.4312 28.0942,-45.4105"></path>
<polygon fill="black" stroke="black" points="31.4067,-46.6014 32.627,-36.0771 25.11,-43.5433 31.4067,-46.6014"></polygon>
<text text-anchor="middle" x="29.8821" y="-57.8" font-family="menlo" font-size="14.00">x</text>
</g>
<g id="edge2" class="edge"><title>A:se->O</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M57.3821,-90C68.8965,-78.4856 65.1632,-60.4312 58.6701,-45.4105"></path>
<polygon fill="black" stroke="black" points="61.6543,-43.5433 54.1372,-36.0771 55.3576,-46.6014 61.6543,-43.5433"></polygon>
<text text-anchor="middle" x="68.8821" y="-57.8" font-family="menlo" font-size="14.00">y</text>
</g>
</g>
</svg>
</figure>
<p>We’ve determined that the reference <code class="highlighter-rouge">x</code> we’re aliasing from isn’t an issue, but
we also need to consider existing references other than <code class="highlighter-rouge">x</code> as well.</p>
<p>We use the fact that the heap was well-formed before we created the alias. By
the definition of well-formed heaps, no other actor had access to that object.
While there could be another reference <code class="highlighter-rouge">z</code> to that object, it must come from the
same actor as <code class="highlighter-rouge">x</code>, and therefore <code class="highlighter-rouge">y</code>. The resulting heap is still well-formed.</p>
<figure class="good-heap">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="95pt" height="131pt" viewBox="0.00 0.00 94.76 131.00">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 127)">
<title>%3</title>
<g id="node1" class="node"><title>A</title>
<polygon fill="none" stroke="black" points="0.117544,-99.4377 43.3821,-87 86.6467,-99.4377 86.6063,-119.562 0.157926,-119.562 0.117544,-99.4377"></polygon>
<text text-anchor="middle" x="43.3821" y="-101.3" font-family="menlo" font-size="14.00">Actor</text>
</g>
<g id="node2" class="node"><title>O</title>
<polygon fill="none" stroke="black" points="74.3821,-36 12.3821,-36 12.3821,-0 74.3821,-0 74.3821,-36"></polygon>
<text text-anchor="middle" x="43.3821" y="-14.3" font-family="menlo" font-size="14.00">Object</text>
</g>
<g id="edge1" class="edge"><title>A:sw->O</title>
<path fill="none" stroke="black" d="M29.3821,-90C17.1256,-77.7435 8.50439,-70.3063 14.3821,-54 15.5687,-50.7081 17.2144,-47.5064 19.1244,-44.4626"></path>
<polygon fill="black" stroke="black" points="21.9724,-46.4973 25.046,-36.3581 16.3204,-42.3676 21.9724,-46.4973"></polygon>
<text text-anchor="middle" x="18.3821" y="-57.8" font-family="menlo" font-size="14.00">z</text>
</g>
<g id="edge2" class="edge"><title>A->O</title>
<path fill="none" stroke="black" d="M43.3821,-86.799C43.3821,-75.1626 43.3821,-59.5479 43.3821,-46.2368"></path>
<polygon fill="black" stroke="black" points="46.8822,-46.1754 43.3821,-36.1754 39.8822,-46.1755 46.8822,-46.1754"></polygon>
<text text-anchor="middle" x="47.8821" y="-57.8" font-family="menlo" font-size="14.00">x</text>
</g>
<g id="edge3" class="edge"><title>A:se->O</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M57.3821,-90C68.8965,-78.4856 65.1632,-60.4312 58.6701,-45.4105"></path>
<polygon fill="black" stroke="black" points="61.6543,-43.5433 54.1372,-36.0771 55.3576,-46.6014 61.6543,-43.5433"></polygon>
<text text-anchor="middle" x="68.8821" y="-57.8" font-family="menlo" font-size="14.00">y</text>
</g>
</g>
</svg>
</figure>
<h3 id="message-passing">Message passing</h3>
<div class="language-pony highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// x points to an object
</span><span class="nc">Foo</span><span class="p">.</span><span class="n">bar</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
<span class="kr">actor</span> <span class="nc">Foo</span>
<span class="kr">be</span> <span class="n">bar</span><span class="p">(</span><span class="n">y</span><span class="o">:</span> <span class="nc">Counter</span><span class="p">)</span> <span class="o">=></span> <span class="p">...</span>
</code></pre></div></div>
<p>The last operation we need to consider is message passing. This is actually two
operations, the sending actor writes the message to a queue and the receiving
one later reads the message from the queue and executes the corresponding
behaviour. However for the sake of simplicity we’ll look at this as a single
combined one (this way we don’t have to model the message queue).</p>
<p>When we pass the message with an argument, the receiving actor starts having
access to the object this argument references. Because the sending actor also
has a reference to it, there are now two actors which can access the same
object, breaking well-formedness!</p>
<figure class="bad-heap">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="260pt" height="131pt" viewBox="0.00 0.00 260.29 131.00">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 127)">
<title>%3</title>
<g id="node1" class="node"><title>A1</title>
<polygon fill="none" stroke="black" points="-0.129664,-99.4377 54.6294,-87 109.388,-99.4377 109.337,-119.562 -0.0785533,-119.562 -0.129664,-99.4377"></polygon>
<text text-anchor="middle" x="54.6294" y="-101.3" font-family="menlo" font-size="14.00">Sender</text>
</g>
<g id="node3" class="node"><title>O</title>
<polygon fill="none" stroke="black" points="152.629,-36 90.6294,-36 90.6294,-0 152.629,-0 152.629,-36"></polygon>
<text text-anchor="middle" x="121.629" y="-14.3" font-family="menlo" font-size="14.00">Object</text>
</g>
<g id="edge1" class="edge"><title>A1->O</title>
<path fill="none" stroke="black" d="M65.995,-89.5809C75.7324,-77.2275 89.9858,-59.1449 101.628,-44.3755"></path>
<polygon fill="black" stroke="black" points="104.685,-46.1509 108.126,-36.1307 99.1871,-41.8176 104.685,-46.1509"></polygon>
<text text-anchor="middle" x="97.1294" y="-57.8" font-family="menlo" font-size="14.00">x</text>
</g>
<g id="node2" class="node"><title>A2</title>
<polygon fill="none" stroke="black" points="126.803,-99.4377 189.629,-87 252.456,-99.4377 252.397,-119.562 126.861,-119.562 126.803,-99.4377"></polygon>
<text text-anchor="middle" x="189.629" y="-101.3" font-family="menlo" font-size="14.00">Receiver</text>
</g>
<g id="edge2" class="edge"><title>A2->O</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M177.785,-89.1941C167.924,-76.8682 153.66,-59.0377 141.975,-44.4322"></path>
<polygon fill="black" stroke="black" points="144.427,-41.8937 135.447,-36.2714 138.96,-46.2666 144.427,-41.8937"></polygon>
<text text-anchor="middle" x="164.129" y="-57.8" font-family="menlo" font-size="14.00">y</text>
</g>
</g>
</svg>
</figure>
<p>We could be tempted to fix this by modifying our language’s semantics such that
sending a message <em>consumes</em> the argument. In other words, doing <code class="highlighter-rouge">Foo.bar(x)</code>
“kills” the <code class="highlighter-rouge">x</code> variable and any attempt to reuse it results in a compile time
error. This way the sender loses access to the object and well-formedness would
be preserved.</p>
<div class="language-pony highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Foo</span><span class="p">.</span><span class="n">bar</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
<span class="n">x</span><span class="p">.</span><span class="n">increment</span><span class="p">()</span> <span class="c1">// error: x has been consumed
</span></code></pre></div></div>
<p>Unfortunately, the well-formedness of the original heap does not guarantee that
<code class="highlighter-rouge">x</code> is the only reference to that object. Indeed, there could be another alias
<code class="highlighter-rouge">z</code> which would persist even if we made <code class="highlighter-rouge">x</code> unusable.</p>
<figure class="bad-heap">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="260pt" height="131pt" viewBox="0.00 0.00 260.29 131.00">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 127)">
<title>%3</title>
<g id="node1" class="node"><title>A1</title>
<polygon fill="none" stroke="black" points="-0.129664,-99.4377 54.6294,-87 109.388,-99.4377 109.337,-119.562 -0.0785533,-119.562 -0.129664,-99.4377"></polygon>
<text text-anchor="middle" x="54.6294" y="-101.3" font-family="menlo" font-size="14.00">Sender</text>
</g>
<g id="node3" class="node"><title>O</title>
<polygon fill="none" stroke="black" points="101.629,-36 39.6294,-36 39.6294,-0 101.629,-0 101.629,-36"></polygon>
<text text-anchor="middle" x="70.6294" y="-14.3" font-family="menlo" font-size="14.00">Object</text>
</g>
<g id="edge1" class="edge"><title>A1:sw->O</title>
<path fill="none" stroke="black" d="M39.6294,-89C27.3382,-76.7088 35.6957,-58.7071 46.8123,-44.0373"></path>
<polygon fill="black" stroke="black" points="49.5307,-46.242 53.1585,-36.2876 44.1149,-41.807 49.5307,-46.242"></polygon>
<text text-anchor="middle" x="43.6294" y="-57.8" font-family="menlo" font-size="14.00">z</text>
</g>
<g id="edge2" class="edge"><title>A1:se->O</title>
<path fill="none" stroke="black" d="M69.6294,-89C80.4869,-78.1425 80.8716,-60.9534 78.4759,-46.3262"></path>
<polygon fill="black" stroke="black" points="81.84,-45.3168 76.35,-36.2554 74.9909,-46.7627 81.84,-45.3168"></polygon>
<text text-anchor="middle" x="85.1294" y="-57.8" font-family="menlo" font-size="14.00">x</text>
</g>
<g id="node2" class="node"><title>A2</title>
<polygon fill="none" stroke="black" points="126.803,-99.4377 189.629,-87 252.456,-99.4377 252.397,-119.562 126.861,-119.562 126.803,-99.4377"></polygon>
<text text-anchor="middle" x="189.629" y="-101.3" font-family="menlo" font-size="14.00">Receiver</text>
</g>
<g id="edge3" class="edge"><title>A2->O</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M170.773,-90.5315C152.606,-77.5551 124.756,-57.662 103.033,-42.1456"></path>
<polygon fill="black" stroke="black" points="104.915,-39.1886 94.7433,-36.2242 100.846,-44.8847 104.915,-39.1886"></polygon>
<text text-anchor="middle" x="142.129" y="-57.8" font-family="menlo" font-size="14.00">y</text>
</g>
</g>
</svg>
</figure>
<p>For the moment we’ll simply disallow sending messages with arguments. It makes
the language a lot less powerful by heavily limiting how actors can
communicate, but at least well-formedness is preserved.</p>
<div class="language-pony highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Foo</span><span class="p">.</span><span class="n">bar</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="c1">// error: cannot send messages with arguments
</span><span class="nc">Foo</span><span class="p">.</span><span class="n">baz</span><span class="p">()</span> <span class="c1">// ok
</span></code></pre></div></div>
<h2 id="conclusion">Conclusion</h2>
<p>Thanks to our definition of well-formed heaps, and by showing that it gets
preserved during any of our execution steps, any program written in
<em>Little Pony</em> is guaranteed to be free of data-races!</p>
<p>The flip-side is that we’ve had to disallow message passing with arguments. This
severly limits what kind of program you can write, making it unusable for most
practical purposes.</p>
<p>In the next post I’ll talk about how we can improve our type system to fix this,
by introducing immutable objects. Stay tuned!</p>
<p>If you have any questions or comments feel free to email me at <a href="mailto:paul@lietar.net">paul@lietar.net</a>.
Alternatively you can share them on <a href="https://twitter.com/lietarp/status/975546151624683521">twitter</a> or <a href="https://www.reddit.com/r/ponylang/comments/85fxgj/how_to_train_your_pony_introduction/">reddit</a>.</p>
<figure>
<img src="https://media.giphy.com/media/ZPKA8hg390ZP2/giphy.gif" />
</figure>Paul LiétarThis article is the first in a series of blog posts about the Pony language’s type system, with a focus on the capability system.