The Digital Cat - Erlanghttps://www.thedigitalcatonline.com/2013-06-20T17:49:00+01:00Adventures of a curious cat in the land of programmingThe Lord of the Rings: an Erlang epic2013-06-20T17:49:00+01:002013-06-20T17:49:00+01:00Leonardo Giordanitag:www.thedigitalcatonline.com,2013-06-20:/blog/2013/06/20/the-lord-of-the-rings-an-erlang-epic/<h2 id="abstract">Abstract<a class="headerlink" href="#abstract" title="Permanent link">¶</a></h2>
<p>One of the first really challenging problems an Erlang novice must face is the classical process ring, which can be found around the Internet and most notably in "Erlang Programming" by Cesarini and Thompson (page 115).</p>
<p>Its formulation may vary, but the core of it requires the programmer to design and implement a closed ring of processes, to make them pass a given number of messages each other and then terminate gracefully.</p>
<p>I try here to give an in-depth analysis of the matter, to point out some of the most interesting issues of this exercise. I strongly suggest the Erlang novice to try and solve the exercise before looking at the solutions proposed here.</p>
<h2 id="linking-processes">Linking processes<a class="headerlink" href="#linking-processes" title="Permanent link">¶</a></h2>
<p>The aim of the exercise is to build a chain of processes that exchange messages. The latter specification is important since we are required to connect our processes with the only purpose of sending messages and we know that, in Erlang, a process may send a message to another process simply by knowing its pid.</p>
<p>Actual linking between processes, in Erlang, has the aim of making them exchange <em>exit signals</em>; links are thus a mean to control the way the system collapses (or not) when a process crashes. The processes in the ring will thus be linked to ensure that when one of them exits all other processes will be terminated, but this has nothing to do with the ring itself.</p>
<p>The point is to let a process know how to send a message to the next one, forming a chain. This chain, then, is closed, i.e. the last process sends messages to the first one.</p>
<p>There are two main strategies that can be leveraged to get the ring build and behave in a correct way: the <strong>master process</strong> approach and the <strong>recursive</strong> one. For each of the two, I am going to present and analyze the following steps: a ring of processes with <strong>no message</strong> exchange, a ring with <strong>a single message</strong> travelling through it, a ring with <strong>multiple messages</strong> and a ring that exposes a <strong>functional interface</strong> to send messages.</p>
<h2 id="debugging">Debugging<a class="headerlink" href="#debugging" title="Permanent link">¶</a></h2>
<p>Debugging concurrent applications is everything but simple. For this exercise, it is however enough to get simple information about which process is forwarding which message. To allow a simple removal of debug prints a very small macro has been included in the file <code>debug.hrl</code>, activated by the definition of <code>debug</code>.</p>
<div class="highlight"><pre><span></span><code><span class="p">-</span><span class="ni">ifdef</span><span class="p">(</span><span class="n">debug</span><span class="p">).</span>
<span class="p">-</span><span class="ni">define</span><span class="p">(</span><span class="no">DEBUG</span><span class="p">(</span><span class="nv">Format</span><span class="p">,</span><span class="w"> </span><span class="nv">Args</span><span class="p">),</span>
<span class="w"> </span><span class="nn">io</span><span class="p">:</span><span class="nf">format</span><span class="p">(</span><span class="s">"</span><span class="si">~p</span><span class="s">: "</span><span class="w"> </span><span class="o">++</span><span class="w"> </span><span class="nv">Format</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="n">self</span><span class="p">()]</span><span class="w"> </span><span class="o">++</span><span class="w"> </span><span class="nv">Args</span><span class="p">)).</span>
<span class="p">-</span><span class="ni">else</span><span class="p">.</span>
<span class="p">-</span><span class="ni">define</span><span class="p">(</span><span class="no">DEBUG</span><span class="p">(</span><span class="nv">Format</span><span class="p">,</span><span class="w"> </span><span class="nv">Args</span><span class="p">),</span><span class="w"> </span><span class="n">true</span><span class="p">).</span>
<span class="p">-</span><span class="ni">endif</span><span class="p">.</span>
</code></pre></div>
<p>This converts the line</p>
<div class="highlight"><pre><span></span><code><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"A message</span><span class="si">~n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="p">[]).</span>
</code></pre></div>
<p>to</p>
<div class="highlight"><pre><span></span><code><<span class="m">0</span>.44.0>:<span class="w"> </span>A<span class="w"> </span>message
</code></pre></div>
<p>where <code><0.44.0></code> is the pid of the message calling <code>?DEBUG</code> (only if <code>-define(debug, true).</code> is in the file).</p>
<h2 id="the-master-process-solution">The “master process” solution<a class="headerlink" href="#the-master-process-solution" title="Permanent link">¶</a></h2>
<p>A good way to face the problem of building the ring is to spawn a <em>master process</em>, which will then spawn all other processes. This solution keeps the creation phase simple since everything happens between the master process and the process that is currently being spawned.</p>
<p>A small caveat: the creation of the ring must be performed <strong>backwards</strong>. When the master process spawns another process the only other process it knows is the process spawned in the previous loop. This means that the master process spawns a process that connects backwards to it, then spawns a process that connects backward to the second one, and so on.</p>
<h4 id="building-the-ring">Building the ring<a class="headerlink" href="#building-the-ring" title="Permanent link">¶</a></h4>
<div class="highlight"><pre><span></span><code><span class="c">%%% Author: Leonardo Giordani <giordani.leonardo@gmail.com></span>
<span class="c">%%% Description: Implements a simple ring of processes without message passing</span>
<span class="c">%%% Created: Jun 2013 by Leonardo Giordani</span>
<span class="p">-</span><span class="ni">module</span><span class="p">(</span><span class="n">ring_master_no_messages</span><span class="p">).</span>
<span class="c">%% Include some debug macros</span>
<span class="p">-</span><span class="ni">define</span><span class="p">(</span><span class="no">debug</span><span class="p">,</span><span class="w"> </span><span class="n">true</span><span class="p">).</span>
<span class="p">-</span><span class="ni">include</span><span class="p">(</span><span class="s">"debug.hrl"</span><span class="p">).</span>
<span class="c">%% User interface</span>
<span class="p">-</span><span class="ni">export</span><span class="p">([</span><span class="n">start</span><span class="o">/</span><span class="mi">1</span><span class="p">]).</span>
<span class="c">%% Private exports</span>
<span class="p">-</span><span class="ni">export</span><span class="p">([</span><span class="n">create</span><span class="o">/</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">create</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="n">loop</span><span class="o">/</span><span class="mi">1</span><span class="p">]).</span>
<span class="c">%% This version of the processes ring program uses the first process as a</span>
<span class="c">%% master that spawns all other processes. It links to each process it spawns,</span>
<span class="c">%% but processes are not linked each other.</span>
<span class="c">%% Processes send no messages.</span>
<span class="c">%% This spawns the first process. There is no need to register the process.</span>
<span class="nf">start</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="nb">spawn</span><span class="p">(</span><span class="o">?</span><span class="nv">MODULE</span><span class="p">,</span><span class="w"> </span><span class="n">create</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nv">NumberProcesses</span><span class="p">]).</span>
<span class="c">%% Function create/1 needs to be defined so that the first process can call</span>
<span class="c">%% create/2 passing its pid through self().</span>
<span class="nf">create</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="n">create</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="p">,</span><span class="w"> </span><span class="n">self</span><span class="p">()).</span>
<span class="c">%% Function create/2 manages the single process creation; in this version the</span>
<span class="c">%% master process just spawns each process and links to it. The exit clause</span>
<span class="c">%% is when the proceses counter reaches 1 (that is, we completed the ring).</span>
<span class="nf">create</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="nv">NextProcess</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Process </span><span class="si">~p</span><span class="s"> connected with </span><span class="si">~p~n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="n">self</span><span class="p">(),</span><span class="w"> </span><span class="nv">NextProcess</span><span class="p">]),</span>
<span class="w"> </span><span class="n">loop</span><span class="p">(</span><span class="nv">NextProcess</span><span class="p">);</span>
<span class="nf">create</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="p">,</span><span class="w"> </span><span class="nv">NextProcess</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="nv">Prev</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">spawn_link</span><span class="p">(</span><span class="o">?</span><span class="nv">MODULE</span><span class="p">,</span><span class="w"> </span><span class="n">loop</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nv">NextProcess</span><span class="p">]),</span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Process </span><span class="si">~p</span><span class="s"> created and connected with </span><span class="si">~p~n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nv">Prev</span><span class="p">,</span><span class="w"> </span><span class="nv">NextProcess</span><span class="p">]),</span>
<span class="w"> </span><span class="n">create</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="nv">Prev</span><span class="p">).</span>
<span class="c">%% In this version function loop/1 sits down and does nothing.</span>
<span class="nf">loop</span><span class="p">(</span><span class="nv">NextProcess</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="n">loop</span><span class="p">(</span><span class="nv">NextProcess</span><span class="p">).</span>
</code></pre></div>
<p><a href="/code/erlang-rings/ring_master_no_messages.erl">source code</a></p>
<p>Note that the first spawn cannot directly call <code>create/2</code> passing <code>self()</code> since at that moment <code>self()</code> is the pid of the calling process (e.g. the Erlang shell) and not the pid of the first process of the ring, which is what we want. So we have to bypass this by spawning a process which executes <code>create/1</code>, which in turn calls <code>create/2</code> with the pid the process extracted with <code>self()</code>.</p>
<p>This first program spawns a set of processes that sit down and do nothing. Since they are all linked together (through the link with the master process), you can terminate the whole set by sending an exit signal to one of them. You can get the list of pid and names through the shell function <code>i()</code>. Otherwise, you can get and use the pid returned by the function <code>start/1</code>.</p>
<div class="highlight"><pre><span></span><code><span class="mi">1</span><span class="o">></span><span class="w"> </span><span class="n">i</span><span class="p">().</span>
<span class="p">[...]</span>
<span class="mi">2</span><span class="o">></span><span class="w"> </span><span class="nb">exit</span><span class="p">(</span><span class="n">pid</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">44</span><span class="p">,</span><span class="mi">0</span><span class="p">),</span><span class="w"> </span><span class="n">boom</span><span class="p">).</span>
</code></pre></div>
<h4 id="sending-a-single-message">Sending a single message<a class="headerlink" href="#sending-a-single-message" title="Permanent link">¶</a></h4>
<p>Now I am going to develop further the solution by making a single message travel the whole ring.</p>
<p>The code undergoes the following modifications:</p>
<ul>
<li>function <code>start()</code> must accept the message and pass it to <code>create()</code>.</li>
<li>function <code>create()</code> must accept the message</li>
<li>when the ring is ready the master process has to send the message to the second process; then it terminates</li>
<li>each node just forwards the incoming message and terminates</li>
</ul>
<div class="highlight"><pre><span></span><code><span class="c">%%% Author: Leonardo Giordani <giordani.leonardo@gmail.com></span>
<span class="c">%%% Description: Implements a simple ring of processes with a single</span>
<span class="c">%%% message traveling once through the ring.</span>
<span class="c">%%% Created: Jun 2013 by Leonardo Giordani</span>
<span class="p">-</span><span class="ni">module</span><span class="p">(</span><span class="n">ring_master_single_message</span><span class="p">).</span>
<span class="c">%% Include some debug macros</span>
<span class="p">-</span><span class="ni">define</span><span class="p">(</span><span class="no">debug</span><span class="p">,</span><span class="w"> </span><span class="n">true</span><span class="p">).</span>
<span class="p">-</span><span class="ni">include</span><span class="p">(</span><span class="s">"debug.hrl"</span><span class="p">).</span>
<span class="c">%% User interface</span>
<span class="p">-</span><span class="ni">export</span><span class="p">([</span><span class="n">start</span><span class="o">/</span><span class="mi">2</span><span class="p">]).</span>
<span class="c">%% Private exports</span>
<span class="p">-</span><span class="ni">export</span><span class="p">([</span><span class="n">create</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="n">create</span><span class="o">/</span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="n">loop</span><span class="o">/</span><span class="mi">1</span><span class="p">]).</span>
<span class="c">%% This version of the processes ring program uses the first process as a</span>
<span class="c">%% master that spawns all other processes. It links to each process it spawns,</span>
<span class="c">%% but processes are not linked each other.</span>
<span class="c">%% The first process then injects a single message in the ring, sending it to</span>
<span class="c">%% the second process.</span>
<span class="c">%% This spawns the first process. There is no need to register the process.</span>
<span class="nf">start</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="p">,</span><span class="w"> </span><span class="nv">Message</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="nb">spawn</span><span class="p">(</span><span class="o">?</span><span class="nv">MODULE</span><span class="p">,</span><span class="w"> </span><span class="n">create</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nv">NumberProcesses</span><span class="p">,</span><span class="w"> </span><span class="nv">Message</span><span class="p">]).</span>
<span class="c">%% Function create/2 needs to be defined so that the first process can call</span>
<span class="c">%% create/3 passing its pid through self().</span>
<span class="nf">create</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="p">,</span><span class="w"> </span><span class="nv">Message</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="n">create</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="p">,</span><span class="w"> </span><span class="n">self</span><span class="p">(),</span><span class="w"> </span><span class="nv">Message</span><span class="p">).</span>
<span class="c">%% Function create/3 manages the single process creation; in this version the</span>
<span class="c">%% master process spawns each process and links to it. Then each process starts</span>
<span class="c">%% a loop. When the ring is completed the first process injects the message and</span>
<span class="c">%% terminates.</span>
<span class="nf">create</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="nv">NextProcess</span><span class="p">,</span><span class="w"> </span><span class="nv">Message</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Process </span><span class="si">~p</span><span class="s"> connected with </span><span class="si">~p~n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="n">self</span><span class="p">(),</span><span class="w"> </span><span class="nv">NextProcess</span><span class="p">]),</span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Process </span><span class="si">~p</span><span class="s"> injects message </span><span class="si">~p~n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="n">self</span><span class="p">(),</span><span class="w"> </span><span class="nv">Message</span><span class="p">]),</span>
<span class="w"> </span><span class="nv">NextProcess</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="nv">Message</span><span class="p">;</span>
<span class="nf">create</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="p">,</span><span class="w"> </span><span class="nv">NextProcess</span><span class="p">,</span><span class="w"> </span><span class="nv">Message</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="nv">Prev</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">spawn_link</span><span class="p">(</span><span class="o">?</span><span class="nv">MODULE</span><span class="p">,</span><span class="w"> </span><span class="n">loop</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nv">NextProcess</span><span class="p">]),</span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Process </span><span class="si">~p</span><span class="s"> created and connected with </span><span class="si">~p~n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nv">Prev</span><span class="p">,</span><span class="w"> </span><span class="nv">NextProcess</span><span class="p">]),</span>
<span class="w"> </span><span class="n">create</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="nv">Prev</span><span class="p">,</span><span class="w"> </span><span class="nv">Message</span><span class="p">).</span>
<span class="c">%% Now loop/1 blocks each process making it wait for a message to pass along.</span>
<span class="nf">loop</span><span class="p">(</span><span class="nv">NextProcess</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="k">receive</span>
<span class="w"> </span><span class="nv">Msg</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Got message </span><span class="si">~p</span><span class="s">, passing it to </span><span class="si">~p~n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nv">Msg</span><span class="p">,</span><span class="w"> </span><span class="nv">NextProcess</span><span class="p">]),</span>
<span class="w"> </span><span class="nv">NextProcess</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="nv">Msg</span><span class="p">,</span>
<span class="w"> </span><span class="n">ok</span>
<span class="w"> </span><span class="k">end</span><span class="p">.</span>
</code></pre></div>
<p><a href="/code/erlang-rings/ring_master_single_message.erl">source code</a></p>
<p>Beware that a subtle mechanism conceals here: in Erlang, you can always send a message to a pid, even if it the relative process does not exist; in the latter case the message is simply discarded. This feature allows us to make the first process send the message and terminate without having the last process crash by sending a message to it. Remember that you cannot do this with registered processes alias, only with pids.</p>
<h4 id="sending-multiple-messages">Sending multiple messages<a class="headerlink" href="#sending-multiple-messages" title="Permanent link">¶</a></h4>
<p>The exercise requests that a message can travel more than once through the whole ring. Adding this possibility is pretty straightforward: it simply requires to add a parameter to <code>start()</code> and <code>create()</code> and to change the loop clauses.</p>
<p>Function <code>loop/1</code> now becomes <code>loop/2</code> and has the following clauses:</p>
<ul>
<li>when the number of remaining travels is 1 the process forwards the message and then terminates.</li>
<li>when the number of remaining travels is more than 1 the process loops again with a decremented value of travels.</li>
</ul>
<div class="highlight"><pre><span></span><code><span class="c">%%% Author: Leonardo Giordani <giordani.leonardo@gmail.com></span>
<span class="c">%%% Description: Implements a simple ring of processes with a single</span>
<span class="c">%%% message traveling multiple times through the ring.</span>
<span class="c">%%% Created: Jun 2013 by Leonardo Giordani</span>
<span class="p">-</span><span class="ni">module</span><span class="p">(</span><span class="n">ring_master_multiple_messages</span><span class="p">).</span>
<span class="c">%% Include some debug macros</span>
<span class="p">-</span><span class="ni">define</span><span class="p">(</span><span class="no">debug</span><span class="p">,</span><span class="w"> </span><span class="n">true</span><span class="p">).</span>
<span class="p">-</span><span class="ni">include</span><span class="p">(</span><span class="s">"debug.hrl"</span><span class="p">).</span>
<span class="c">%% User interface</span>
<span class="p">-</span><span class="ni">export</span><span class="p">([</span><span class="n">start</span><span class="o">/</span><span class="mi">3</span><span class="p">]).</span>
<span class="c">%% Private exports</span>
<span class="p">-</span><span class="ni">export</span><span class="p">([</span><span class="n">create</span><span class="o">/</span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="n">create</span><span class="o">/</span><span class="mi">4</span><span class="p">,</span><span class="w"> </span><span class="n">loop</span><span class="o">/</span><span class="mi">2</span><span class="p">]).</span>
<span class="c">%% This version of the processes ring program uses the first process as a</span>
<span class="c">%% master that spawns all other processes. It links to each process it spawns,</span>
<span class="c">%% but processes are not linked each other.</span>
<span class="c">%% The first process then injects a message in the ring, sending it to the</span>
<span class="c">%% second process and when getting the message from the last process, it</span>
<span class="c">%% injects it again in the ring a given number of times.</span>
<span class="c">%% This spawns the first process. There is no need to register the process.</span>
<span class="nf">start</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="p">,</span><span class="w"> </span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="nv">NumberMessages</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="nb">spawn</span><span class="p">(</span><span class="o">?</span><span class="nv">MODULE</span><span class="p">,</span><span class="w"> </span><span class="n">create</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nv">NumberProcesses</span><span class="p">,</span><span class="w"> </span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="nv">NumberMessages</span><span class="p">]).</span>
<span class="c">%% Function create/3 needs to be defined so that the first process can call</span>
<span class="c">%% create/4 passing its pid through self().</span>
<span class="nf">create</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="p">,</span><span class="w"> </span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="nv">NumberMessages</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="n">create</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="p">,</span><span class="w"> </span><span class="n">self</span><span class="p">(),</span><span class="w"> </span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="nv">NumberMessages</span><span class="p">).</span>
<span class="c">%% Function create/4 manages the single process creation; in this version the</span>
<span class="c">%% master process spawns each process and links to it. Then each process starts</span>
<span class="c">%% a loop. When the ring is completed the first process injects the message and</span>
<span class="c">%% starts looping.</span>
<span class="nf">create</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="nv">NextProcess</span><span class="p">,</span><span class="w"> </span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="nv">NumberMessages</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Process </span><span class="si">~p</span><span class="s"> connected with </span><span class="si">~p~n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="n">self</span><span class="p">(),</span><span class="w"> </span><span class="nv">NextProcess</span><span class="p">]),</span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Process </span><span class="si">~p</span><span class="s"> injects message </span><span class="si">~p~n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="n">self</span><span class="p">(),</span><span class="w"> </span><span class="nv">Message</span><span class="p">]),</span>
<span class="w"> </span><span class="nv">NextProcess</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="nv">Message</span><span class="p">,</span>
<span class="w"> </span><span class="n">loop</span><span class="p">(</span><span class="nv">NextProcess</span><span class="p">,</span><span class="w"> </span><span class="nv">NumberMessages</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span>
<span class="nf">create</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="p">,</span><span class="w"> </span><span class="nv">NextProcess</span><span class="p">,</span><span class="w"> </span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="nv">NumberMessages</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="nv">Prev</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">spawn_link</span><span class="p">(</span><span class="o">?</span><span class="nv">MODULE</span><span class="p">,</span><span class="w"> </span><span class="n">loop</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nv">NextProcess</span><span class="p">,</span><span class="w"> </span><span class="nv">NumberMessages</span><span class="p">]),</span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Process </span><span class="si">~p</span><span class="s"> created and connected with </span><span class="si">~p~n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nv">Prev</span><span class="p">,</span><span class="w"> </span><span class="nv">NextProcess</span><span class="p">]),</span>
<span class="w"> </span><span class="n">create</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="nv">Prev</span><span class="p">,</span><span class="w"> </span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="nv">NumberMessages</span><span class="p">).</span>
<span class="nf">loop</span><span class="p">(</span><span class="nv">NextProcess</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="k">receive</span>
<span class="w"> </span><span class="nv">Msg</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Got message </span><span class="si">~p</span><span class="s">, passing it to </span><span class="si">~p</span><span class="s"> and terminating</span><span class="si">~n</span><span class="s">"</span><span class="p">,</span>
<span class="w"> </span><span class="p">[</span><span class="nv">Msg</span><span class="p">,</span><span class="w"> </span><span class="nv">NextProcess</span><span class="p">]),</span>
<span class="w"> </span><span class="nv">NextProcess</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="nv">Msg</span><span class="p">,</span>
<span class="w"> </span><span class="n">ok</span>
<span class="w"> </span><span class="k">end</span><span class="p">;</span>
<span class="nf">loop</span><span class="p">(</span><span class="nv">NextProcess</span><span class="p">,</span><span class="w"> </span><span class="nv">NumberMessages</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="k">receive</span>
<span class="w"> </span><span class="nv">Msg</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Got message </span><span class="si">~p</span><span class="s">, passing it to </span><span class="si">~p</span><span class="s"> (still </span><span class="si">~p</span><span class="s"> time(s))</span><span class="si">~n</span><span class="s">"</span><span class="p">,</span>
<span class="w"> </span><span class="p">[</span><span class="nv">Msg</span><span class="p">,</span><span class="w"> </span><span class="nv">NextProcess</span><span class="p">,</span><span class="w"> </span><span class="nv">NumberMessages</span><span class="p">]),</span>
<span class="w"> </span><span class="nv">NextProcess</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="nv">Msg</span><span class="p">,</span>
<span class="w"> </span><span class="n">loop</span><span class="p">(</span><span class="nv">NextProcess</span><span class="p">,</span><span class="w"> </span><span class="nv">NumberMessages</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span>
<span class="w"> </span><span class="k">end</span><span class="p">.</span>
</code></pre></div>
<p><a href="/code/erlang-rings/ring_master_multiple_messages.erl">source code</a></p>
<p>As before, we are here relying on the possibility of sending a message to a non existent process.</p>
<h4 id="exposing-a-functional-interface">Exposing a functional interface<a class="headerlink" href="#exposing-a-functional-interface" title="Permanent link">¶</a></h4>
<p>An Erlang best practice is to expose a functional interface to the user that hides the underlying message passing. We are going to convert our ring program to expose the following functions:</p>
<ul>
<li><code>start/1</code> - starts a ring with the given number of processes</li>
<li><code>stop/0</code> - terminates all processes in the ring</li>
<li><code>send_message/1</code> - sends a message that travels once through the ring</li>
<li><code>send_message/2</code> - sends a message that travels the given number of times through the ring</li>
</ul>
<p>To expose a functional interface you need to register one or more processes, to get a global access point for your functions, so the first change to the code is that the spawned process is registered. Note that <code>Message</code> and <code>NumberProcesses</code> are no more passed to the <code>create()</code> function.</p>
<div class="highlight"><pre><span></span><code><span class="nb">register</span><span class="p">(</span><span class="n">ring_master_functional</span><span class="p">,</span><span class="w"> </span><span class="nb">spawn</span><span class="p">(</span><span class="o">?</span><span class="nv">MODULE</span><span class="p">,</span><span class="w"> </span><span class="n">create</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nv">NumberProcesses</span><span class="p">])),</span>
</code></pre></div>
<p>This is not enough. We have to be sure that the whole ring is ready before giving control back to the user issuing <code>start()</code>. Until now the message was sent by the master process just after the creation of the last ring process, so there was no need to synchronize the return of the start function with the spawned processes. Now we need it, so just after registering the master process we wait for a ready message coming from the ring. To allow the ring to send the message to the initial caller we have to pass <code>self()</code> to <code>create()</code>. Pay attention that <code>self()</code> passed to the spawned process is the pid of the external process (e.g. the Erlang shell) while <code>self()</code> passed to <code>create()</code> is the pid of the master ring process.</p>
<div class="highlight"><pre><span></span><code><span class="c">%%% Author: Leonardo Giordani <giordani.leonardo@gmail.com></span>
<span class="c">%%% Description: Implements a simple ring of processes that exposes a</span>
<span class="c">%%% functional interface to send messages.</span>
<span class="c">%%% Created: Jun 2013 by Leonardo Giordani</span>
<span class="p">-</span><span class="ni">module</span><span class="p">(</span><span class="n">ring_master_functional</span><span class="p">).</span>
<span class="c">%% Include some debug macros</span>
<span class="c">%%-define(debug, true).</span>
<span class="p">-</span><span class="ni">include</span><span class="p">(</span><span class="s">"debug.hrl"</span><span class="p">).</span>
<span class="c">%% User interface</span>
<span class="p">-</span><span class="ni">export</span><span class="p">([</span><span class="n">start</span><span class="o">/</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">stop</span><span class="o">/</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">send_message</span><span class="o">/</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">send_message</span><span class="o">/</span><span class="mi">2</span><span class="p">]).</span>
<span class="c">%% Private exports</span>
<span class="p">-</span><span class="ni">export</span><span class="p">([</span><span class="n">create</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="n">loop</span><span class="o">/</span><span class="mi">1</span><span class="p">]).</span>
<span class="c">%% This version of the processes ring program uses the first process as a</span>
<span class="c">%% master that spawns all other processes. It links to each process it spawns,</span>
<span class="c">%% but processes are not linked each other.</span>
<span class="c">%% The module exposes a functional interface to send messages in the ring</span>
<span class="c">%% and to terminate it.</span>
<span class="c">%% This spawns the first process. The process is registered to allow the</span>
<span class="c">%% functional interface to work with it.</span>
<span class="nf">start</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="nb">register</span><span class="p">(</span><span class="n">ring_master_functional</span><span class="p">,</span><span class="w"> </span><span class="nb">spawn</span><span class="p">(</span><span class="o">?</span><span class="nv">MODULE</span><span class="p">,</span><span class="w"> </span><span class="n">create</span><span class="p">,</span>
<span class="w"> </span><span class="p">[</span><span class="nv">NumberProcesses</span><span class="p">,</span><span class="w"> </span><span class="n">self</span><span class="p">()])),</span>
<span class="w"> </span><span class="k">receive</span>
<span class="w"> </span><span class="n">ready</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="n">ok</span>
<span class="w"> </span><span class="k">after</span><span class="w"> </span><span class="mi">5000</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="p">{</span><span class="n">error</span><span class="p">,</span><span class="w"> </span><span class="n">timeout</span><span class="p">}</span>
<span class="w"> </span><span class="k">end</span><span class="p">.</span>
<span class="c">%% Functional interface: terminate the ring</span>
<span class="nf">stop</span><span class="p">()</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="n">ring_master_functional</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="p">{</span><span class="n">command</span><span class="p">,</span><span class="w"> </span><span class="n">stop</span><span class="p">}.</span>
<span class="c">%% Functional interface: send a message that travels through the ring once</span>
<span class="nf">send_message</span><span class="p">(</span><span class="nv">Message</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="n">send_message</span><span class="p">(</span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">).</span>
<span class="c">%% Functional interface: send a message that travels through the ring</span>
<span class="c">%% Times times</span>
<span class="nf">send_message</span><span class="p">(</span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="nv">Times</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="n">ring_master_functional</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="p">{</span><span class="n">command</span><span class="p">,</span><span class="w"> </span><span class="n">message</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="nv">Times</span><span class="p">]}.</span>
<span class="c">%% Function create/2 needs to be defined so that the first process can call</span>
<span class="c">%% create/3 passing its pid through self(). The Starter process is passed to</span>
<span class="c">%% allow the ring to send a ready message.</span>
<span class="nf">create</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="p">,</span><span class="w"> </span><span class="nv">Starter</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="n">create</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="p">,</span><span class="w"> </span><span class="n">self</span><span class="p">(),</span><span class="w"> </span><span class="nv">Starter</span><span class="p">).</span>
<span class="c">%% Function create/3 manages the single process creation; in this version the</span>
<span class="c">%% master process spawns each process and links to it. Then each process starts</span>
<span class="c">%% a loop. When the ring is completed the first process injects the message and</span>
<span class="c">%% terminates.</span>
<span class="nf">create</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="nv">NextProcess</span><span class="p">,</span><span class="w"> </span><span class="nv">Starter</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Process </span><span class="si">~p</span><span class="s"> connected with </span><span class="si">~p~n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="n">self</span><span class="p">(),</span><span class="w"> </span><span class="nv">NextProcess</span><span class="p">]),</span>
<span class="w"> </span><span class="nv">Starter</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="n">ready</span><span class="p">,</span>
<span class="w"> </span><span class="n">loop_master</span><span class="p">(</span><span class="nv">NextProcess</span><span class="p">);</span>
<span class="nf">create</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="p">,</span><span class="w"> </span><span class="nv">NextProcess</span><span class="p">,</span><span class="w"> </span><span class="nv">Starter</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="nv">Prev</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">spawn_link</span><span class="p">(</span><span class="o">?</span><span class="nv">MODULE</span><span class="p">,</span><span class="w"> </span><span class="n">loop</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nv">NextProcess</span><span class="p">]),</span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Process </span><span class="si">~p</span><span class="s"> created and connected with </span><span class="si">~p~n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nv">Prev</span><span class="p">,</span><span class="w"> </span><span class="nv">NextProcess</span><span class="p">]),</span>
<span class="w"> </span><span class="n">create</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="nv">Prev</span><span class="p">,</span><span class="w"> </span><span class="nv">Starter</span><span class="p">).</span>
<span class="c">%% Function loop_master/1 rules the behaviour of the master process (the first</span>
<span class="c">%% of the whole ring). When it receives a stop command it forwards it and</span>
<span class="c">%% terminates. When it receives a message command if Times is 0 the message is</span>
<span class="c">%% thrown away, otherwise is is injected again in the ring with a decremented</span>
<span class="c">%% Times value.</span>
<span class="nf">loop_master</span><span class="p">(</span><span class="nv">NextProcess</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="k">receive</span>
<span class="w"> </span><span class="nv">Msg</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="n">command</span><span class="p">,</span><span class="w"> </span><span class="n">stop</span><span class="p">}</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="nv">NextProcess</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="nv">Msg</span><span class="p">,</span>
<span class="w"> </span><span class="n">ok</span><span class="p">;</span>
<span class="w"> </span><span class="p">{</span><span class="n">command</span><span class="p">,</span><span class="w"> </span><span class="n">message</span><span class="p">,</span><span class="w"> </span><span class="p">[_</span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">]}</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="n">loop_master</span><span class="p">(</span><span class="nv">NextProcess</span><span class="p">);</span>
<span class="w"> </span><span class="p">{</span><span class="n">command</span><span class="p">,</span><span class="w"> </span><span class="n">message</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="nv">Times</span><span class="p">]}</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Got message </span><span class="si">~p</span><span class="s">, passing it to </span><span class="si">~p</span><span class="s"> (still </span><span class="si">~p</span><span class="s"> time(s)</span><span class="si">~n</span><span class="s">"</span><span class="p">,</span>
<span class="w"> </span><span class="p">[</span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="nv">NextProcess</span><span class="p">,</span><span class="w"> </span><span class="nv">Times</span><span class="p">]),</span>
<span class="w"> </span><span class="nv">NextProcess</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="p">{</span><span class="n">command</span><span class="p">,</span><span class="w"> </span><span class="n">message</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="nv">Times</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">]},</span>
<span class="w"> </span><span class="n">loop_master</span><span class="p">(</span><span class="nv">NextProcess</span><span class="p">)</span>
<span class="w"> </span><span class="k">end</span><span class="p">.</span>
<span class="c">%% Function loop/1 rules the behaviour of the standard processes.</span>
<span class="c">%% When a process receives a stop command it forwards it and</span>
<span class="c">%% terminates. When it receives a message command it just forwards it.</span>
<span class="nf">loop</span><span class="p">(</span><span class="nv">NextProcess</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="k">receive</span>
<span class="w"> </span><span class="nv">Msg</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="n">command</span><span class="p">,</span><span class="w"> </span><span class="n">stop</span><span class="p">}</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="nv">NextProcess</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="nv">Msg</span><span class="p">,</span>
<span class="w"> </span><span class="n">ok</span><span class="p">;</span>
<span class="w"> </span><span class="nv">Msg</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="n">command</span><span class="p">,</span><span class="w"> </span><span class="n">message</span><span class="p">,</span><span class="w"> </span><span class="p">[_</span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="p">_]}</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Got message </span><span class="si">~p</span><span class="s">, passing it to </span><span class="si">~p~n</span><span class="s">"</span><span class="p">,</span>
<span class="w"> </span><span class="p">[_</span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="nv">NextProcess</span><span class="p">]),</span>
<span class="w"> </span><span class="nv">NextProcess</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="nv">Msg</span><span class="p">,</span>
<span class="w"> </span><span class="n">loop</span><span class="p">(</span><span class="nv">NextProcess</span><span class="p">)</span>
<span class="w"> </span><span class="k">end</span><span class="p">.</span>
</code></pre></div>
<p><a href="/code/erlang-rings/ring_master_functional.erl">source code</a></p>
<p>The exposed functions are very simple. As you can see they use two different messages: <code>{command, stop}</code> and <code>{command, message, [Message, Times]}</code>. One of the advantages of exposing a functional API is that you are free to format your messages according to the current status of the software and change the format if it does no more suit the application needs.</p>
<p>The <code>loop()</code> function has been splitted in two different functions now: <code>loop/1</code> rules the behaviour of the standard ring process, while <code>loop_master/1</code> rules the behaviour of the master process.</p>
<p>The standard process has to react to a stop command, forwarding it and terminating, and to a message command, simply forwarding it. The master process has to check an incoming message to decide if it shall be injected again in the ring.</p>
<h2 id="a-recursive-solution">A recursive solution<a class="headerlink" href="#a-recursive-solution" title="Permanent link">¶</a></h2>
<p>The simplest way to make a process know the pid of another process is to let the first spawn the second, and this gives us a hint about another way the process ring can be built. Like many things in Erlang, this can be solved recursively by saying:</p>
<p>In a process do:</p>
<ul>
<li>spawn another process and store its pid, call recursively on the spawned process</li>
<li>if you are the last process just connect to the first</li>
</ul>
<p>This solution has the advantage of being very straightforward for an Erlang programmer since it implements the standard recursion pattern. However, it forces the programmer to deal most of the time with the last node, which is a little counterintuitive.</p>
<p>The following programs are the recursive version of the four presented in the previous section. Once grasped the two main differences, building the ring forwards instead of backwards and dealing with the last node instead of the first, the two solutions present pretty much the same evolution steps.</p>
<p>The recursive ring construction.</p>
<div class="highlight"><pre><span></span><code><span class="c">%%% Author: Leonardo Giordani <giordani.leonardo@gmail.com></span>
<span class="c">%%% Description: Implements a simple ring of processes without message passing</span>
<span class="c">%%% Created: Jun 2013 by Leonardo Giordani</span>
<span class="p">-</span><span class="ni">module</span><span class="p">(</span><span class="n">ring_recursion_no_messages</span><span class="p">).</span>
<span class="c">%% Include some debug macros</span>
<span class="p">-</span><span class="ni">define</span><span class="p">(</span><span class="no">debug</span><span class="p">,</span><span class="w"> </span><span class="n">true</span><span class="p">).</span>
<span class="p">-</span><span class="ni">include</span><span class="p">(</span><span class="s">"debug.hrl"</span><span class="p">).</span>
<span class="c">%% User interface</span>
<span class="p">-</span><span class="ni">export</span><span class="p">([</span><span class="n">start</span><span class="o">/</span><span class="mi">1</span><span class="p">]).</span>
<span class="c">%% Private exports</span>
<span class="p">-</span><span class="ni">export</span><span class="p">([</span><span class="n">create</span><span class="o">/</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">loop</span><span class="o">/</span><span class="mi">1</span><span class="p">]).</span>
<span class="c">%% This version of the processes ring program starts the processes in a</span>
<span class="c">%% recursive way. Each process spawns the next one and links to it.</span>
<span class="c">%% Processes send no messages.</span>
<span class="c">%% Please remember that io:format() does not always respect processes order</span>
<span class="c">%% and that as a general rule printing on the standard output from concurrent</span>
<span class="c">%% jobs is not very useful. Here I do this just to show that processes have been</span>
<span class="c">%% spawned. Remember to define debug false if you create a ring of more than</span>
<span class="c">%% 30-40 processes.</span>
<span class="c">%% This spawns the first process, registering it under the name</span>
<span class="c">%% 'ring_recursion_no_messages'.</span>
<span class="c">%% Note that spawn() does never fail, but register may; if spawning the</span>
<span class="c">%% first process fails an exception is raised and the process calling</span>
<span class="c">%% start/1 is terminated.</span>
<span class="nf">start</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="nb">register</span><span class="p">(</span><span class="n">ring_recursion_no_messages</span><span class="p">,</span><span class="w"> </span><span class="nb">spawn</span><span class="p">(</span><span class="o">?</span><span class="nv">MODULE</span><span class="p">,</span><span class="w"> </span><span class="n">create</span><span class="p">,</span>
<span class="w"> </span><span class="p">[</span><span class="nv">NumberProcesses</span><span class="p">])).</span>
<span class="c">%% Function create/1 manages the single process creation; in this version the</span>
<span class="c">%% only thing a process shall do is to spawn another process. The exit clause</span>
<span class="c">%% is when the proceses counter reaches 1 (that is, the current process is the</span>
<span class="c">%% last one): the last process uses 'ring_recursion_no_messages' as its next</span>
<span class="c">%% process, thus closing the ring.</span>
<span class="c">%% Here we use the only parameter(NumberProcesses) as the index for the current</span>
<span class="c">%% process, so we end when the parameter is 1. If we want to think of it as the</span>
<span class="c">%% number of REMAINING processes the only changes are that the exit clause is</span>
<span class="c">%% create(0) instead of create(1), and that the first process is spawned in</span>
<span class="c">%% start/1 with [NumberProcesses - 1] as argument. It is only a matter of taste.</span>
<span class="c">%% Since all processes in the ring are meant to work together we are linking</span>
<span class="c">%% them together to ensure that if one fails all others are terminated.</span>
<span class="nf">create</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Process </span><span class="si">~p</span><span class="s"> created and connected with </span><span class="si">~p</span><span class="s"> (last)</span><span class="si">~n</span><span class="s">"</span><span class="p">,</span>
<span class="w"> </span><span class="p">[</span><span class="n">self</span><span class="p">(),</span><span class="w"> </span><span class="nb">whereis</span><span class="p">(</span><span class="n">ring_recursion_no_messages</span><span class="p">)]),</span>
<span class="w"> </span><span class="n">loop</span><span class="p">(</span><span class="n">ring_recursion_no_messages</span><span class="p">);</span>
<span class="nf">create</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="nv">Next</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">spawn_link</span><span class="p">(</span><span class="o">?</span><span class="nv">MODULE</span><span class="p">,</span><span class="w"> </span><span class="n">create</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nv">NumberProcesses</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">]),</span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Process </span><span class="si">~p</span><span class="s"> created and connected with </span><span class="si">~p</span><span class="s"> </span><span class="si">~n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="n">self</span><span class="p">(),</span><span class="w"> </span><span class="nv">Next</span><span class="p">]),</span>
<span class="w"> </span><span class="n">loop</span><span class="p">(</span><span class="nv">Next</span><span class="p">).</span>
<span class="c">%% In this version function loop/1 sits down and does nothing.</span>
<span class="nf">loop</span><span class="p">(</span><span class="nv">NextProcess</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="n">loop</span><span class="p">(</span><span class="nv">NextProcess</span><span class="p">).</span>
</code></pre></div>
<p><a href="/code/erlang-rings/ring_recursion_no_messages.erl">source code</a></p>
<p>The recursive ring with a single message travelling.</p>
<div class="highlight"><pre><span></span><code><span class="c">%%% Author: Leonardo Giordani <giordani.leonardo@gmail.com></span>
<span class="c">%%% Description: Implements a simple ring of processes with a single</span>
<span class="c">%%% message traveling once through the ring.</span>
<span class="c">%%% Created: Jun 2013 by Leonardo Giordani</span>
<span class="p">-</span><span class="ni">module</span><span class="p">(</span><span class="n">ring_recursion_single_message</span><span class="p">).</span>
<span class="c">%% Include some debug macros</span>
<span class="p">-</span><span class="ni">define</span><span class="p">(</span><span class="no">debug</span><span class="p">,</span><span class="w"> </span><span class="n">true</span><span class="p">).</span>
<span class="p">-</span><span class="ni">include</span><span class="p">(</span><span class="s">"debug.hrl"</span><span class="p">).</span>
<span class="c">%% User interface</span>
<span class="p">-</span><span class="ni">export</span><span class="p">([</span><span class="n">start</span><span class="o">/</span><span class="mi">2</span><span class="p">]).</span>
<span class="c">%% Private exports</span>
<span class="p">-</span><span class="ni">export</span><span class="p">([</span><span class="n">create</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="n">loop</span><span class="o">/</span><span class="mi">1</span><span class="p">]).</span>
<span class="c">%% This version of the processes ring program starts the processes in a</span>
<span class="c">%% recursive way. Each process spawns the next one and links to it.</span>
<span class="c">%% The last process then injects a single message in the ring, sending it to the</span>
<span class="c">%% first process.</span>
<span class="c">%% This spawns the first process passing the requested message to it</span>
<span class="nf">start</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="p">,</span><span class="w"> </span><span class="nv">Message</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="nb">register</span><span class="p">(</span><span class="n">ring_recursion_single_message</span><span class="p">,</span><span class="w"> </span><span class="nb">spawn</span><span class="p">(</span><span class="o">?</span><span class="nv">MODULE</span><span class="p">,</span><span class="w"> </span><span class="n">create</span><span class="p">,</span>
<span class="w"> </span><span class="p">[</span><span class="nv">NumberProcesses</span><span class="p">,</span><span class="w"> </span><span class="nv">Message</span><span class="p">])).</span>
<span class="c">%% Function create/2 manages the single process creation; in this version each</span>
<span class="c">%% process just spawns another process, except the last one, which shall inject</span>
<span class="c">%% the message in the ring and terminate.</span>
<span class="nf">create</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="nv">Message</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Process </span><span class="si">~p</span><span class="s"> created and connected with </span><span class="si">~p</span><span class="s"> (last)</span><span class="si">~n</span><span class="s">"</span><span class="p">,</span>
<span class="w"> </span><span class="p">[</span><span class="n">self</span><span class="p">(),</span><span class="w"> </span><span class="nb">whereis</span><span class="p">(</span><span class="n">ring_recursion_single_message</span><span class="p">)]),</span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Process </span><span class="si">~p</span><span class="s"> injects message </span><span class="si">~p~n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="n">self</span><span class="p">(),</span><span class="w"> </span><span class="nv">Message</span><span class="p">]),</span>
<span class="w"> </span><span class="n">ring_recursion_single_message</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="nv">Message</span><span class="p">;</span>
<span class="nf">create</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="p">,</span><span class="w"> </span><span class="nv">Message</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="nv">Next</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">spawn_link</span><span class="p">(</span><span class="o">?</span><span class="nv">MODULE</span><span class="p">,</span><span class="w"> </span><span class="n">create</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nv">NumberProcesses</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="nv">Message</span><span class="p">]),</span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Process </span><span class="si">~p</span><span class="s"> created and connected with </span><span class="si">~p</span><span class="s"> </span><span class="si">~n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="n">self</span><span class="p">(),</span><span class="w"> </span><span class="nv">Next</span><span class="p">]),</span>
<span class="w"> </span><span class="n">loop</span><span class="p">(</span><span class="nv">Next</span><span class="p">).</span>
<span class="c">%% Now loop/1 blocks each process making it wait for a message to pass along.</span>
<span class="nf">loop</span><span class="p">(</span><span class="nv">NextProcess</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="k">receive</span>
<span class="w"> </span><span class="nv">Msg</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Got message </span><span class="si">~p</span><span class="s">, passing it to </span><span class="si">~p~n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nv">Msg</span><span class="p">,</span><span class="w"> </span><span class="nv">NextProcess</span><span class="p">]),</span>
<span class="w"> </span><span class="nv">NextProcess</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="nv">Msg</span><span class="p">,</span>
<span class="w"> </span><span class="n">ok</span>
<span class="w"> </span><span class="k">end</span><span class="p">.</span>
</code></pre></div>
<p><a href="/code/erlang-rings/ring_recursion_single_message.erl">source code</a></p>
<p>The recursive ring with support for multiple message travels.</p>
<div class="highlight"><pre><span></span><code><span class="c">%%% Author: Leonardo Giordani <giordani.leonardo@gmail.com></span>
<span class="c">%%% Description: Implements a simple ring of processes with a single</span>
<span class="c">%%% message traveling multiple times through the ring.</span>
<span class="c">%%% Created: Jun 2013 by Leonardo Giordani</span>
<span class="p">-</span><span class="ni">module</span><span class="p">(</span><span class="n">ring_recursion_multiple_messages</span><span class="p">).</span>
<span class="c">%% Include some debug macros</span>
<span class="p">-</span><span class="ni">define</span><span class="p">(</span><span class="no">debug</span><span class="p">,</span><span class="w"> </span><span class="n">true</span><span class="p">).</span>
<span class="p">-</span><span class="ni">include</span><span class="p">(</span><span class="s">"debug.hrl"</span><span class="p">).</span>
<span class="c">%% User interface</span>
<span class="p">-</span><span class="ni">export</span><span class="p">([</span><span class="n">start</span><span class="o">/</span><span class="mi">3</span><span class="p">]).</span>
<span class="c">%% Private exports</span>
<span class="p">-</span><span class="ni">export</span><span class="p">([</span><span class="n">create</span><span class="o">/</span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="n">loop</span><span class="o">/</span><span class="mi">2</span><span class="p">]).</span>
<span class="c">%% This version of the processes ring program starts the processes in a</span>
<span class="c">%% recursive way. Each process spawns the next one and links to it.</span>
<span class="c">%% The last process then injects a message in the ring, sending it to the</span>
<span class="c">%% first process and when getting the message from the second to last, it</span>
<span class="c">%% injects it again in the ring a given number of times.</span>
<span class="c">%% This spawns the first process passing it the requested message and the number</span>
<span class="c">%% of times the message shall travel through the ring.</span>
<span class="nf">start</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="p">,</span><span class="w"> </span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="nv">NumberMessages</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="nb">register</span><span class="p">(</span><span class="n">ring_recursion_multiple_messages</span><span class="p">,</span><span class="w"> </span><span class="nb">spawn</span><span class="p">(</span><span class="o">?</span><span class="nv">MODULE</span><span class="p">,</span><span class="w"> </span><span class="n">create</span><span class="p">,</span>
<span class="w"> </span><span class="p">[</span><span class="nv">NumberProcesses</span><span class="p">,</span><span class="w"> </span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="nv">NumberMessages</span><span class="p">])).</span>
<span class="c">%% Function create/3 manages the single process creation; in this version each</span>
<span class="c">%% process spawns another process and then loops, except the last one, which</span>
<span class="c">%% shall inject the message in the ring before looping. Since the last process</span>
<span class="c">%% starts the message passing it loops an already decremented number of times.</span>
<span class="nf">create</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="nv">NumberMessages</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Process </span><span class="si">~p</span><span class="s"> created and connected with </span><span class="si">~p</span><span class="s"> (last)</span><span class="si">~n</span><span class="s">"</span><span class="p">,</span>
<span class="w"> </span><span class="p">[</span><span class="n">self</span><span class="p">(),</span><span class="w"> </span><span class="nb">whereis</span><span class="p">(</span><span class="n">ring_recursion_multiple_messages</span><span class="p">)]),</span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Process </span><span class="si">~p</span><span class="s"> injects message </span><span class="si">~p~n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="n">self</span><span class="p">(),</span><span class="w"> </span><span class="nv">Message</span><span class="p">]),</span>
<span class="w"> </span><span class="n">ring_recursion_multiple_messages</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="nv">Message</span><span class="p">,</span>
<span class="w"> </span><span class="n">loop</span><span class="p">(</span><span class="n">ring_recursion_multiple_messages</span><span class="p">,</span><span class="w"> </span><span class="nv">NumberMessages</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span>
<span class="nf">create</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="p">,</span><span class="w"> </span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="nv">NumberMessages</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="nv">Next</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">spawn_link</span><span class="p">(</span><span class="o">?</span><span class="nv">MODULE</span><span class="p">,</span><span class="w"> </span><span class="n">create</span><span class="p">,</span>
<span class="w"> </span><span class="p">[</span><span class="nv">NumberProcesses</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="nv">NumberMessages</span><span class="p">]),</span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Process </span><span class="si">~p</span><span class="s"> created and connected with </span><span class="si">~p</span><span class="s"> </span><span class="si">~n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="n">self</span><span class="p">(),</span><span class="w"> </span><span class="nv">Next</span><span class="p">]),</span>
<span class="w"> </span><span class="n">loop</span><span class="p">(</span><span class="nv">Next</span><span class="p">,</span><span class="w"> </span><span class="nv">NumberMessages</span><span class="p">).</span>
<span class="c">%% Function loop/2 needs two clauses now. The first one is the exit condition,</span>
<span class="c">%% when the forward counter reaches 1: the process forwards the message and</span>
<span class="c">%% terminates. The second clause is the standard behaviour: the process forwards</span>
<span class="c">%% the incoming message and loops again with a decremented counter.</span>
<span class="nf">loop</span><span class="p">(</span><span class="nv">NextProcess</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="k">receive</span>
<span class="w"> </span><span class="nv">Msg</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Got message </span><span class="si">~p</span><span class="s">, passing it to </span><span class="si">~p</span><span class="s"> and terminating</span><span class="si">~n</span><span class="s">"</span><span class="p">,</span>
<span class="w"> </span><span class="p">[</span><span class="nv">Msg</span><span class="p">,</span><span class="w"> </span><span class="nv">NextProcess</span><span class="p">]),</span>
<span class="w"> </span><span class="nv">NextProcess</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="nv">Msg</span><span class="p">,</span>
<span class="w"> </span><span class="n">ok</span>
<span class="w"> </span><span class="k">end</span><span class="p">;</span>
<span class="nf">loop</span><span class="p">(</span><span class="nv">NextProcess</span><span class="p">,</span><span class="w"> </span><span class="nv">NumberMessages</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="k">receive</span>
<span class="w"> </span><span class="nv">Msg</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Got message </span><span class="si">~p</span><span class="s">, passing it to </span><span class="si">~p</span><span class="s"> (still </span><span class="si">~p</span><span class="s"> time(s))</span><span class="si">~n</span><span class="s">"</span><span class="p">,</span>
<span class="w"> </span><span class="p">[</span><span class="nv">Msg</span><span class="p">,</span><span class="w"> </span><span class="nv">NextProcess</span><span class="p">,</span><span class="w"> </span><span class="nv">NumberMessages</span><span class="p">]),</span>
<span class="w"> </span><span class="nv">NextProcess</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="nv">Msg</span><span class="p">,</span>
<span class="w"> </span><span class="n">loop</span><span class="p">(</span><span class="nv">NextProcess</span><span class="p">,</span><span class="w"> </span><span class="nv">NumberMessages</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span>
<span class="w"> </span><span class="k">end</span><span class="p">.</span>
</code></pre></div>
<p><a href="/code/erlang-rings/ring_recursion_multiple_messages.erl">source code</a></p>
<p>The recursive ring exposing the functional API.</p>
<div class="highlight"><pre><span></span><code><span class="c">%%% Author: Leonardo Giordani <giordani.leonardo@gmail.com></span>
<span class="c">%%% Description: Implements a simple ring of processes that exposes a</span>
<span class="c">%%% functional interface to send messages.</span>
<span class="c">%%% Created: Jun 2013 by Leonardo Giordani</span>
<span class="p">-</span><span class="ni">module</span><span class="p">(</span><span class="n">ring_recursion_functional</span><span class="p">).</span>
<span class="c">%% Include some debug macros</span>
<span class="p">-</span><span class="ni">define</span><span class="p">(</span><span class="no">debug</span><span class="p">,</span><span class="w"> </span><span class="n">true</span><span class="p">).</span>
<span class="p">-</span><span class="ni">include</span><span class="p">(</span><span class="s">"debug.hrl"</span><span class="p">).</span>
<span class="c">%% User interface</span>
<span class="p">-</span><span class="ni">export</span><span class="p">([</span><span class="n">start</span><span class="o">/</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">stop</span><span class="o">/</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">send_message</span><span class="o">/</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">send_message</span><span class="o">/</span><span class="mi">2</span><span class="p">]).</span>
<span class="c">%% Private exports</span>
<span class="p">-</span><span class="ni">export</span><span class="p">([</span><span class="n">create</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="n">loop</span><span class="o">/</span><span class="mi">1</span><span class="p">]).</span>
<span class="c">%% This version of the processes ring program starts the processes in a</span>
<span class="c">%% recursive way. Each process spawns the next one and links to it.</span>
<span class="c">%% The module exposes a functional interface to send messages in the ring</span>
<span class="c">%% and to terminate it.</span>
<span class="c">%% This spawns the first process. The process is registered as in the previous</span>
<span class="c">%% recursive versions to allow the last process to connect with the first.</span>
<span class="c">%% Moreover, exposing a functional interface needs a global entry point, that is</span>
<span class="c">%% the name of the first process.</span>
<span class="nf">start</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="nb">register</span><span class="p">(</span><span class="n">ring_recursion_functional</span><span class="p">,</span><span class="w"> </span><span class="nb">spawn</span><span class="p">(</span><span class="o">?</span><span class="nv">MODULE</span><span class="p">,</span><span class="w"> </span><span class="n">create</span><span class="p">,</span>
<span class="w"> </span><span class="p">[</span><span class="nv">NumberProcesses</span><span class="p">,</span><span class="w"> </span><span class="n">self</span><span class="p">()])),</span>
<span class="w"> </span><span class="k">receive</span>
<span class="w"> </span><span class="n">ready</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="n">ok</span>
<span class="w"> </span><span class="k">after</span><span class="w"> </span><span class="mi">5000</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="p">{</span><span class="n">error</span><span class="p">,</span><span class="w"> </span><span class="n">timeout</span><span class="p">}</span>
<span class="w"> </span><span class="k">end</span><span class="p">.</span>
<span class="c">%% Functional interface: terminate the ring</span>
<span class="nf">stop</span><span class="p">()</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="n">ring_master_functional</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="p">{</span><span class="n">command</span><span class="p">,</span><span class="w"> </span><span class="n">stop</span><span class="p">}.</span>
<span class="c">%% Functional interface: send a message that travels through the ring once</span>
<span class="nf">send_message</span><span class="p">(</span><span class="nv">Message</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="n">send_message</span><span class="p">(</span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">).</span>
<span class="c">%% Functional interface: send a message that travels through the ring</span>
<span class="c">%% Times times</span>
<span class="nf">send_message</span><span class="p">(</span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="nv">Times</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="n">ring_recursion_functional</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="p">{</span><span class="n">command</span><span class="p">,</span><span class="w"> </span><span class="n">message</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="nv">Times</span><span class="p">]}.</span>
<span class="c">%% Function create/2 manages the single process creation; in this version each</span>
<span class="c">%% process just spawns another process, except the last one, which connects with</span>
<span class="c">%% the first one. The Starter process is passed to allow the ring to send a</span>
<span class="c">%% ready message.</span>
<span class="nf">create</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="nv">Starter</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Process </span><span class="si">~p</span><span class="s"> created and connected with </span><span class="si">~p</span><span class="s"> (last)</span><span class="si">~n</span><span class="s">"</span><span class="p">,</span>
<span class="w"> </span><span class="p">[</span><span class="n">self</span><span class="p">(),</span><span class="w"> </span><span class="nb">whereis</span><span class="p">(</span><span class="n">ring_recursion_functional</span><span class="p">)]),</span>
<span class="w"> </span><span class="nv">Starter</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="n">ready</span><span class="p">,</span>
<span class="w"> </span><span class="n">loop_last</span><span class="p">(</span><span class="n">ring_recursion_functional</span><span class="p">);</span>
<span class="nf">create</span><span class="p">(</span><span class="nv">NumberProcesses</span><span class="p">,</span><span class="w"> </span><span class="nv">Starter</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="nv">Next</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">spawn_link</span><span class="p">(</span><span class="o">?</span><span class="nv">MODULE</span><span class="p">,</span><span class="w"> </span><span class="n">create</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nv">NumberProcesses</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="nv">Starter</span><span class="p">]),</span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Process </span><span class="si">~p</span><span class="s"> created and connected with </span><span class="si">~p</span><span class="s"> </span><span class="si">~n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="n">self</span><span class="p">(),</span><span class="w"> </span><span class="nv">Next</span><span class="p">]),</span>
<span class="w"> </span><span class="n">loop</span><span class="p">(</span><span class="nv">Next</span><span class="p">).</span>
<span class="c">%% Function loop_last/1 rules the behaviour of the last process of the whole</span>
<span class="c">%% ring). When it receives a stop command it just terminates since the message</span>
<span class="c">%% has already been received by all processes in the ring. When it receives a</span>
<span class="c">%% message command if Times is 1 the message is thrown away (it just travelled</span>
<span class="c">%% through the ring for the last time), otherwise is is injected again in the</span>
<span class="c">%% ring with a decremented Times value.</span>
<span class="nf">loop_last</span><span class="p">(</span><span class="nv">NextProcess</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="k">receive</span>
<span class="w"> </span><span class="p">{</span><span class="n">command</span><span class="p">,</span><span class="w"> </span><span class="n">stop</span><span class="p">}</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="n">ok</span><span class="p">;</span>
<span class="w"> </span><span class="p">{</span><span class="n">command</span><span class="p">,</span><span class="w"> </span><span class="n">message</span><span class="p">,</span><span class="w"> </span><span class="p">[_</span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">]}</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="n">loop_last</span><span class="p">(</span><span class="nv">NextProcess</span><span class="p">);</span>
<span class="w"> </span><span class="p">{</span><span class="n">command</span><span class="p">,</span><span class="w"> </span><span class="n">message</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="nv">Times</span><span class="p">]}</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Got message </span><span class="si">~p</span><span class="s">, passing it to </span><span class="si">~p</span><span class="s"> (still </span><span class="si">~p</span><span class="s"> time(s)</span><span class="si">~n</span><span class="s">"</span><span class="p">,</span>
<span class="w"> </span><span class="p">[</span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="nv">NextProcess</span><span class="p">,</span><span class="w"> </span><span class="nv">Times</span><span class="p">]),</span>
<span class="w"> </span><span class="nv">NextProcess</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="p">{</span><span class="n">command</span><span class="p">,</span><span class="w"> </span><span class="n">message</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="nv">Times</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">]},</span>
<span class="w"> </span><span class="n">loop_last</span><span class="p">(</span><span class="nv">NextProcess</span><span class="p">)</span>
<span class="w"> </span><span class="k">end</span><span class="p">.</span>
<span class="c">%% Function loop/1 rules the behaviour of the standard processes.</span>
<span class="c">%% When a process receives a stop command it forwards it and</span>
<span class="c">%% terminates. When it receives a message command it just forwards it.</span>
<span class="nf">loop</span><span class="p">(</span><span class="nv">NextProcess</span><span class="p">)</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="k">receive</span>
<span class="w"> </span><span class="nv">Msg</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="n">command</span><span class="p">,</span><span class="w"> </span><span class="n">stop</span><span class="p">}</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="nv">NextProcess</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="nv">Msg</span><span class="p">,</span>
<span class="w"> </span><span class="n">ok</span><span class="p">;</span>
<span class="w"> </span><span class="nv">Msg</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="n">command</span><span class="p">,</span><span class="w"> </span><span class="n">message</span><span class="p">,</span><span class="w"> </span><span class="p">[_</span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="p">_]}</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="o">?</span><span class="nv">DEBUG</span><span class="p">(</span><span class="s">"Got message </span><span class="si">~p</span><span class="s">, passing it to </span><span class="si">~p~n</span><span class="s">"</span><span class="p">,</span>
<span class="w"> </span><span class="p">[_</span><span class="nv">Message</span><span class="p">,</span><span class="w"> </span><span class="nv">NextProcess</span><span class="p">]),</span>
<span class="w"> </span><span class="nv">NextProcess</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="nv">Msg</span><span class="p">,</span>
<span class="w"> </span><span class="n">loop</span><span class="p">(</span><span class="nv">NextProcess</span><span class="p">)</span>
<span class="w"> </span><span class="k">end</span><span class="p">.</span>
</code></pre></div>
<p><a href="/code/erlang-rings/ring_recursion_functional.erl">source code</a></p>
<h2 id="conclusions">Conclusions<a class="headerlink" href="#conclusions" title="Permanent link">¶</a></h2>
<p>The process ring is an exercise that can be solved in many ways (I just presented the two more straightforward ones) but makes the programmer face problems that may later rise in real-world applications. For this reason, it is an invaluable sandbox where the Erlang programmer can try different approaches to solve both the concurrency and the topology problems.</p>
<p>Keep in touch for other Erlang articles on <a href="/categories/erlang/">this page</a>.</p>Error handling in Erlang - a primer2013-05-30T11:41:00+01:002013-05-30T11:41:00+01:00Leonardo Giordanitag:www.thedigitalcatonline.com,2013-05-30:/blog/2013/05/30/error-handling-in-erlang-a-primer/<h2 id="abstract">Abstract<a class="headerlink" href="#abstract" title="Permanent link">¶</a></h2>
<p>This article aims to summarize Erlang error handling both in sequential and in concurrent environments. The targets of this article are novices that, like me, make their first steps into the beautiful world of Erlang. Moreover, I always find that trying to explain things makes me understand them better.</p>
<p>Disclaimer (for Erlang gurus): I'm a complete Erlang novice so please be indulgent with me while you read my thoughts. Corrections and suggestions are welcome!</p>
<h2 id="introduction">Introduction<a class="headerlink" href="#introduction" title="Permanent link">¶</a></h2>
<p>Recently I started studying Erlang; coming from a pure imperative background (C, C++, and Python) I have to say that Erlang has been a surprise and a joy. I did not find something so innovative since long, even if the pure functional part of the language was not totally new since it is available in Python too.</p>
<p>The concept of runtime <em>system</em>, with a support for concurrency built in the language itself, the pattern matching idea and the recursion as a way to implement loops are all very intriguing, so learning them is fun (pun intended, if you do not get it review Erlang anonymous functions).</p>
<p>One of the innovative concepts that ploughed through my imperative mind was that of <em>defensive programming</em> under its formulation in the Erlang tenet "Let it crash". This was something new, partly because I rarely found advice on system organization while learning the foundations of a programming language and partly because about 80% of the code I write has the task of avoiding programs to crash.</p>
<p>I found <a href="http://mazenharake.wordpress.com/2009/09/14/let-it-crash-the-right-way/">this very interesting post</a> of Mazen Harake on the subject. Basically, he clarifies that the Erlang philosophy is not that of just let errors happen and propagate: the point is that the programmer should deal only with errors that are <em>documented</em>. This means that the code specification includes that error as a possibility. Well, it is not my intention to state something already well explained: go and read Mazen's post.</p>
<p>Anyway, before discussing the Erlang way of dealing with code errors, it is necessary to firmly grasp syntax and structures that the language provides.</p>
<h2 id="exceptions-in-erlang">Exceptions in Erlang<a class="headerlink" href="#exceptions-in-erlang" title="Permanent link">¶</a></h2>
<p>The simplest way to make something go wrong when dealing with a computer is to treat it like a sentient being. Joking apart, a good way to crash a program is to execute a division by zero.</p>
<div class="highlight"><pre><span></span><code><span class="mi">1</span><span class="o">></span><span class="w"> </span><span class="mi">1</span><span class="o">/</span><span class="mi">0</span><span class="p">.</span>
<span class="o">**</span><span class="w"> </span><span class="n">exception</span><span class="w"> </span><span class="nn">error</span><span class="p">:</span><span class="w"> </span><span class="n">bad</span><span class="w"> </span><span class="n">argument</span><span class="w"> </span><span class="n">in</span><span class="w"> </span><span class="n">an</span><span class="w"> </span><span class="n">arithmetic</span><span class="w"> </span><span class="n">expression</span>
<span class="w"> </span><span class="n">in</span><span class="w"> </span><span class="n">operator</span><span class="w"> </span><span class="n">'/'</span><span class="o">/</span><span class="mi">2</span>
<span class="w"> </span><span class="n">called</span><span class="w"> </span><span class="n">as</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="mi">0</span>
<span class="mi">2</span><span class="o">></span><span class="w"> </span>
</code></pre></div>
<p>As you can see Erlang does not get mad at your provocation and simply <strong>raises and exception</strong>, i.e. signals that something went wrong, giving some details about why and where it happened. This is not different from what other languages, like Python, do.</p>
<div class="highlight"><pre><span></span><code><span class="gp">>>> </span><span class="mi">1</span><span class="o">/</span><span class="mi">0</span>
<span class="go">Traceback (most recent call last):</span>
File <span class="nb">"<stdin>"</span>, line <span class="m">1</span>, in <span class="n"><module></span>
<span class="gr">ZeroDivisionError</span>: <span class="n">integer division or modulo by zero</span>
<span class="gp">>>> </span>
</code></pre></div>
<p>So exceptions are in Erlang, as in other languages, a "reserved channel" the language uses to propagate errors. If you code in C, you cannot leverage something like exceptions and must rely on return values. This means that you have to format the results of your functions so that they can host a wrong result too and end up returning an <code>int</code> with the error code while functions results are managed by reference.</p>
<p>Back to Erlang. Exceptions crash you program, i.e. they make your program immediately stop, reporting the error to the system process that executed it (usually the OS GUI or a textual shell). Indeed the Erlang shell crashed when you tried to reach for the infinity.</p>
<div class="highlight"><pre><span></span><code><span class="mi">1</span><span class="o">></span><span class="w"> </span><span class="n">self</span><span class="p">().</span>
<span class="o"><</span><span class="mi">0</span><span class="p">.</span><span class="mi">32</span><span class="p">.</span><span class="mi">0</span><span class="o">></span>
<span class="mi">2</span><span class="o">></span><span class="w"> </span><span class="mi">1</span><span class="o">/</span><span class="mi">0</span><span class="p">.</span>
<span class="o">**</span><span class="w"> </span><span class="n">exception</span><span class="w"> </span><span class="nn">error</span><span class="p">:</span><span class="w"> </span><span class="n">bad</span><span class="w"> </span><span class="n">argument</span><span class="w"> </span><span class="n">in</span><span class="w"> </span><span class="n">an</span><span class="w"> </span><span class="n">arithmetic</span><span class="w"> </span><span class="n">expression</span>
<span class="w"> </span><span class="n">in</span><span class="w"> </span><span class="n">operator</span><span class="w"> </span><span class="n">'/'</span><span class="o">/</span><span class="mi">2</span>
<span class="w"> </span><span class="n">called</span><span class="w"> </span><span class="n">as</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="mi">0</span>
<span class="mi">3</span><span class="o">></span><span class="w"> </span><span class="n">self</span><span class="p">().</span>
<span class="o"><</span><span class="mi">0</span><span class="p">.</span><span class="mi">35</span><span class="p">.</span><span class="mi">0</span><span class="o">></span>
<span class="mi">4</span><span class="o">></span><span class="w"> </span>
</code></pre></div>
<p>Remember that in Erlang <code>self()</code> gives you the Erlang PID of the process (not the operating system's one). As you can see the Eshell process crashed and was restarted by some magic behind the scenes.</p>
<p>I hear you mumble that, well, world is not perfect, and errors happen. So how do we deal with this? Shall we crash every time something wrong occurs in our code or is there some way to unravel the knot and happily continue running the code?</p>
<p>This seems to be a question that even Erlang creators wanted to answer, and their answer was: you can, but you shouldn't always. By now, let us drop the "you shouldn't always" part and learn the basics; you can stop an exception before it crashes your pretty program. Before diving into stopping exceptions techniques, let me review the types of exception you may encounter.</p>
<h2 id="exception-types">Exception types<a class="headerlink" href="#exception-types" title="Permanent link">¶</a></h2>
<p>There are three types (or classes) of exceptions in Erlang: <em>throw</em>, <em>error</em>, and <em>exit</em>.</p>
<p>The first, throw, identifies an exception that a called function voluntarily raises (throwing it at you); such exceptions shall be documented, i.e. the documentation of the function you are calling shall state that this exception may be raised and specify under what conditions this may happen. "Shall" here means that if the programmer does not document the exception all sorts of curses will be casted on his or her code forever. As a Python programmer I strongly advice you to read "shall" as "must".</p>
<p>The second exception type, error, signals that something very bad happened in the system, something that was unexpected to the author of the code raising the exception. Even if this type of exception can be raised explicitly, it is usually raised by the Erlang run-time system. If you recall the first example of this post, the division by zero, you can now understand why the shell printed "exception error"; that exception has not been raised by an instruction in the code of the Erlang shell, but from the run-time system itself. This type of exception also contains a stack trace, but I will not cover it in this article.</p>
<p>The third and last exception type, exit, means that your code is being told to stop immediately.</p>
<p>As you can see the real difference between the three types is the communication intent, not a special behaviour. So from the pure theoretical point of view an error exception can be replaced by a throw exception without any side effect. Obviously, the communication intent is not negligible: indeed, as explained before, throw exceptions are usually documented while errors are not intended for being formalized.</p>
<p>In addition to a class, exceptions encompass a <em>reason</em>, that is a valid Erlang item (an atom, an integer, a pid, ...). The reason carries the explanation of the exception, i.e. a detailed insight in what really happened.</p>
<h2 id="dealing-with-exceptions">Dealing with exceptions<a class="headerlink" href="#dealing-with-exceptions" title="Permanent link">¶</a></h2>
<p>Now that we got acquainted with Erlang exception types we may step further into exception management structures and learn how to stop exceptions from crashing our programs. The way of managing exceptions raised by a function called in our code should be familiar to Python, C++, java and Ruby developers (and to many others, probably); the basic Erlang syntax is</p>
<div class="highlight"><pre><span></span><code><span class="k">try</span><span class="w"> </span><span class="o"><</span><span class="n">expressions</span><span class="o">></span><span class="w"> </span><span class="k">of</span>
<span class="w"> </span><span class="o"><</span><span class="n">result_pattern_matching</span><span class="o">></span>
<span class="k">catch</span>
<span class="w"> </span><span class="o"><</span><span class="n">exception_pattern_matching</span><span class="o">></span>
<span class="k">after</span>
<span class="w"> </span><span class="o"><</span><span class="n">after_expressions</span><span class="o">></span>
<span class="k">end</span>
</code></pre></div>
<p>The large part of this structure is well known. Here, <code><expressions></code> is a series of Erlang expressions, comma-separated as usual; the <code><result_pattern_matching></code> part is a classical Erlang pattern matching structure, just like that you write in a case construct; last, the <code><after_expressions></code> is a series of Erlang expressions. The <code><exception_pattern_matching></code> part has a slightly new syntax we will cover in a moment.</p>
<p>The structure works like in other languages: the <code><expressions></code> code is evaluated and the result is pattern matched against <code><result_pattern_matching></code> and the result is returned by the whole <code>try</code> statement. If an exception is raised when evaluating <code><expressions></code>, it is pattern matched against the code listed in <code><exception_pattern_matching></code> and the relative code is executed. Regardless of what happens in the try/catch part the code in <code><after_expressions></code> is executed, and its result is not returned.</p>
<p>The exception matching code has a syntax that is very similar to that of the usual pattern matching, but exceptions are listed in the new form <code>ExceptionType:Reason</code>, where type and reason have been already described in the previous section. When the exception is a run-time error the reason is one of the values listed <a href="http://erlang.org/doc/reference_manual/errors.html#exit_reasons">here</a>.</p>
<p>So the complete form of a try/catch statement in Erlang is the following, where <code>Expressions</code> is always a comma-separated list of Erlang expressions.</p>
<div class="highlight"><pre><span></span><code><span class="k">try</span><span class="w"> </span><span class="nv">Expression1</span><span class="p">,...,</span><span class="nv">ExpressionN</span><span class="w"> </span><span class="k">of</span>
<span class="w"> </span><span class="nv">Pattern1</span><span class="w"> </span><span class="p">[</span><span class="k">when</span><span class="w"> </span><span class="nv">Guard1</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="nv">PatternExpressions1</span><span class="p">;</span>
<span class="w"> </span><span class="nv">Pattern2</span><span class="w"> </span><span class="p">[</span><span class="k">when</span><span class="w"> </span><span class="nv">Guard2</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="nv">PatternExpressions2</span><span class="p">;</span>
<span class="w"> </span><span class="p">...</span>
<span class="w"> </span><span class="nv">PatternN</span><span class="w"> </span><span class="p">[</span><span class="k">when</span><span class="w"> </span><span class="nv">GuardN</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="nv">PatternExpressionN</span>
<span class="k">catch</span>
<span class="w"> </span><span class="nv">ExceptionType</span><span class="p">:</span><span class="nv">Reason1</span><span class="w"> </span><span class="p">[</span><span class="k">when</span><span class="w"> </span><span class="nv">ExceptionGuard1</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="nv">ExceptionExpressions1</span><span class="p">;</span>
<span class="w"> </span><span class="nv">ExceptionType</span><span class="p">:</span><span class="nv">Reason2</span><span class="w"> </span><span class="p">[</span><span class="k">when</span><span class="w"> </span><span class="nv">ExceptionGuard2</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="nv">ExceptionExpressions2</span><span class="p">;</span>
<span class="w"> </span><span class="p">...</span>
<span class="w"> </span><span class="nv">ExceptionType</span><span class="p">:</span><span class="nv">ReasonN</span><span class="w"> </span><span class="p">[</span><span class="k">when</span><span class="w"> </span><span class="nv">ExceptionGuardN</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="nv">ExceptionExpressionsN</span>
<span class="k">after</span>
<span class="w"> </span><span class="nv">AfterExpressions</span>
<span class="k">end</span><span class="p">.</span>
</code></pre></div>
<p>Exceptions pattern matching allows the use of the do-not-care variable <code>_</code> not only for reasons but for also for types. So the following syntax catches all exceptions of type ExceptionType</p>
<div class="highlight"><pre><span></span><code><span class="p">...</span>
<span class="k">catch</span>
<span class="w"> </span><span class="nv">ExceptionType</span><span class="p">:</span><span class="w"> </span><span class="p">_</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="nv">ExceptionExpressions1</span><span class="p">;</span>
<span class="k">end</span>
</code></pre></div>
<p>while the following catches all exceptions</p>
<div class="highlight"><pre><span></span><code><span class="p">...</span>
<span class="k">catch</span>
<span class="w"> </span><span class="p">_:_</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="nv">ExceptionExpressions1</span><span class="p">;</span>
<span class="k">end</span>
</code></pre></div>
<p>I will not cover here the old-style error handling mechanism with <code>catch</code>; the interested reader can find it documented <a href="http://erlang.org/doc/reference_manual/expressions.html#id79206">here</a>.</p>
<h2 id="returning-values-from-trycatch-statements">Returning values from try/catch statements<a class="headerlink" href="#returning-values-from-trycatch-statements" title="Permanent link">¶</a></h2>
<p>Try/catch statements return the value of the last expression executed, that is one of <code>PatternExpression1</code>,...,<code>PatternExpressionN</code> if no exception is raised, or one of <code>ExceptionExpressions1</code>,...,<code>ExceptionExpressionsN</code>. This means that we can assign the value of the whole expression to a variable </p>
<div class="highlight"><pre><span></span><code><span class="nv">Result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">try</span><span class="w"> </span><span class="nv">Expression</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="k">end</span><span class="p">.</span>
</code></pre></div>
<p>Remember that <code>AfterExpressions</code> are always executed, but their final value is not returned by the statement.</p>
<p>Since a lot of times you want to return the result of the expression after the <code>try</code> keyword, you can omit the <code>of</code> part</p>
<div class="highlight"><pre><span></span><code><span class="k">try</span><span class="w"> </span><span class="nv">Expressions</span>
<span class="k">catch</span>
<span class="w"> </span><span class="p">...</span>
<span class="k">end</span><span class="p">.</span>
</code></pre></div>
<h2 id="raising-exceptions">Raising exceptions<a class="headerlink" href="#raising-exceptions" title="Permanent link">¶</a></h2>
<p>Erlang provides three different BIFs to raise exceptions, profitably called like the exception type they raise: <code>throw/1</code>, <code>erlang:error/1</code>, and <code>exit/1</code>. As you see, <code>error/1</code> is not automatically imported by the system and must be called in its full form. This is a hint for us programmers: <code>error/1</code> is there and can be used, but it is not something you should need often; otherwise, you misunderstood what an error exception is in Erlang.</p>
<p>So in most cases, if your code encounters an error condition and you need to raise an exception, you end up using <code>throw/1</code> or <code>exit/1</code>. The argument of these functions is the reason of the exception: remember that you can format the reason you attach to your exception to match your needs, you only need to document it.</p>
<div class="highlight"><pre><span></span><code><span class="nf">my_function</span><span class="p">(</span><span class="nv">Somebadvalue</span><span class="p">)</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">throw</span><span class="p">({</span><span class="n">badvalue</span><span class="p">,</span><span class="w"> </span><span class="nv">Somebadvalue</span><span class="p">}).</span>
</code></pre></div>
<p>Pay attention, however, that exceptions are a double-edged sword; the fact that they return values through a reserved channel is powerful, but can lead to subtle bugs and to long debug sessions. The advice in Erlang is to spare throw() for some special cases and to try always to communicate the failure through standard function results. This is, however, part of a coding philosophy that cannot be examined in depth here.</p>
<h2 id="exceptions-and-exit-signals">Exceptions and exit signals<a class="headerlink" href="#exceptions-and-exit-signals" title="Permanent link">¶</a></h2>
<p>Erlang is a run-time system, not just a language; as such, it has built-in structures and concepts that are usually provided by libraries in other languages. One of these concepts is the dependency between processes, which may be realized through <em>links</em> (and <em>monitors</em>, but I am not going to introduce them in this article). Process linking in Erlang means a very simple thing: when two processes are linked they die together, i.e. when one of the two terminates abnormally the other one is terminated too. A process can link to more than one other process, and the dying behaviour is propagated among all them.</p>
<p>What is the point of this structure? In Erlang, you are encouraged to spawn processes to accomplish tasks, even the simplest ones. Thus, you can easily end up with a multitude of processes working together to perform some action, and if one of them crashes it is likely that others should exit too, being them dependent from it. This is not mandatory; it is all up to you to decide what processes have to be linked, but if they are they must die together.</p>
<p>How is this accomplished? Linked processes are connected by a hidden communication channel, which carries information about their termination with so-called <em>exit signals</em>. Exit signals are invisible to the programmer, and when a process receives one of them it simply terminates, spreading the news under the form of other exit signals.</p>
<h4 id="process-termination-and-reasons">Process termination and reasons<a class="headerlink" href="#process-termination-and-reasons" title="Permanent link">¶</a></h4>
<p>Exit signals are always sent when a process dies, but they carry a reason for its termination, just like exceptions. This reason is very important for the subsequent events concerning processes linked to the dying one.</p>
<p>First of all let us look at process termination. A process in Erlang can terminate normally or abnormally: the former happens when it has no more code to execute or when it raises an exception passing as reason the atom <code>normal</code>; the latter occurs when a raised exception has a reason different from the atom <code>normal</code>.</p>
<p>So an exit signal process contains either the atom <code>normal</code> or another reason, and it travels from the terminating process to each linked process. When it hits one of them, if the reason is not <code>normal</code> the process is terminated and sends its own exit signals to its linked processes with the same reason of the incoming one. The result is that the entire network of linked processes terminates automatically.</p>
<p>The best way to terminate a process with a reason is to execute the BIF <code>exit(Reason)</code>. This BIF has also the form of arity 2 where you pass the pid of a process <code>exit(Pid, Reason)</code>: the addressed process will get an exit signal with the given reason. A caveat: when using <code>exit/1</code> the exit signal will contain the pid of the terminating process, when using <code>exit/2</code> the exit signal will contain the pid of the target process.</p>
<h4 id="stopping-exit-signals">Stopping exit signals<a class="headerlink" href="#stopping-exit-signals" title="Permanent link">¶</a></h4>
<p>Having a way to stop an entire group of processes when one of them crashes is a big benefit, but it could be a good thing to be able to stop the propagation somewhere. Obviously, if processes are not linked they do not influence each other when terminating, but this also means that no one notices that a process terminated, which in turn means that no one will be restarting it.</p>
<p>The whole point of linking processes is indeed the control over terminating processes. If a process runs there is a reason and if it crashes the system should investigate why it crashed and possibly restart it.</p>
<p>Erlang gives a process the chance to receive an abnormal exit signal from a process it is linked to, without forcing it to terminate: in Erlang speech this is called <em>trapping exit signals</em> or <em>trapping exits</em>. When a process traps exits the incoming exit signals coming from linked processes are converted by the run-time system into messages that the process can fetch with a <code>receive</code> construct. Thus, a process trapping exits can be notified that a linked process died without being affected by this.</p>
<p>A process can start trapping exits by executing the BIF <code>process_flag(trap_exit, true)</code>. It is a best practice to call it at the beginning of the process and to avoid turning it off during the execution since it makes the system difficult to debug.</p>
<p>Once the BIF has been executed, an exit signal with the reason <code>Reason</code> coming from another process is converted in an incoming message under the form <code>{'EXIT', Pid, Reason}</code>, where Pid is the pid of the terminated process.</p>
<h4 id="unstoppable-exit-signals">Unstoppable exit signals<a class="headerlink" href="#unstoppable-exit-signals" title="Permanent link">¶</a></h4>
<p>Now we can convert a process so that it does not terminate with its linked processes. This has a downside: if the process contains errors such as infinite loops or if for some reason we need to stop the entire system, the processes that trap exits cannot be stopped. For this reason, Erlang provides the special atom <code>kill</code> as a reason for an exit signal. </p>
<p>An exit signal containing the reason <code>kill</code> cannot be trapped; thus the exit signal is unstoppable. Unconditionally terminating the entire network is however something dangerous, so when a process terminates because of an incoming <code>kill</code> exit signal it will send to its linked processes a <code>killed</code> exit signal, which can be possibly trapped.</p>
<h2 id="conclusions">Conclusions<a class="headerlink" href="#conclusions" title="Permanent link">¶</a></h2>
<p>The aim of the article was to give an overview of error handling in Erlang: not everything has been covered, but a novice should find here almost everything he or she needs to step into this part of the language.</p>
<p>There is obviously much more than this in the Erlang treasure chest. If the whole link and exit signals stuff thrilled you like it did with me, I promise you that OTP behavious (sorry, behaviors) will take your breath away.</p>
<p>Keep in touch for other Erlang articles on <a href="/categories/erlang/">this page</a>.</p>