{"id":602167,"date":"2023-01-28T07:48:59","date_gmt":"2023-01-28T13:48:59","guid":{"rendered":"https:\/\/news.sellorbuyhomefast.com\/index.php\/2023\/01\/28\/erlangs-not-about-lightweight-processes-and-message-passing\/"},"modified":"2023-01-28T07:48:59","modified_gmt":"2023-01-28T13:48:59","slug":"erlangs-not-about-lightweight-processes-and-message-passing","status":"publish","type":"post","link":"https:\/\/newsycanuse.com\/index.php\/2023\/01\/28\/erlangs-not-about-lightweight-processes-and-message-passing\/","title":{"rendered":"Erlang&#8217;s not about lightweight processes and message passing"},"content":{"rendered":"<div id=\"readme\" data-target=\"readme-toc.content\">\n<article itemprop=\"text\">\n<table readabilityDataTable=\"1\">\n<thead>\n<tr>\n<th>date<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\n<p>2023-01-18<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2 dir=\"auto\">Erlang&#8217;s not about lightweight processes and message passing&#8230;<\/h2>\n<p dir=\"auto\">I used to think that the big idea of Erlang is its lightweight processes and<br \/>\nmessage passing. Over the last couple of years I&#8217;ve realised that there&#8217;s a<br \/>\nbigger insight to be had, and in this post I&#8217;d like to share it with you.<\/p>\n<h2 dir=\"auto\">Background<\/h2>\n<p dir=\"auto\">Erlang has an interesting history. If I understand things correctly, it started<br \/>\noff as a Prolog library for building reliable distributed systems, morphed into a<br \/>\nProlog dialect, before finally becoming a language in its own right.<\/p>\n<p dir=\"auto\">The goal seemed to have always been to solve the problem of building reliable<br \/>\ndistributed systems. It was developed at Ericsson and used to program their<br \/>\ntelephone switches. This was sometime in the 80s and 90s, before internet use<br \/>\nbecome widespread. I suppose they were already dealing with &#8220;internet scale&#8221;<br \/>\ntraffic, i.e. hundreds of millions of users, with stricter SLAs than most<br \/>\ninternet services provide today. So in a sense they were ahead of their time.<\/p>\n<p dir=\"auto\">In 1998 Ericsson decided to ban all use of Erlang<sup><a href=\"http:\/\/github.com\/#user-content-fn-0-b236052c3934bd6f7ea3426445bf45af\" id=\"user-content-fnref-0-b236052c3934bd6f7ea3426445bf45af\" data-footnote-ref aria-describedby=\"footnote-label\">1<\/a><\/sup>. The people responsible<br \/>\nfor developing it argued that if they were going to ban it, then they might as<br \/>\nwell open source it. Which Ericsson did and shortly after most of the team that<br \/>\ncreated Erlang quit and started their own company.<\/p>\n<p dir=\"auto\">One of these people was Joe Armstrong, which also was one of the main people<br \/>\nbehind the design and implementation of Erlang. The company was called Bluetail<br \/>\nand they got bought up a couple of times but in the end Joe got fired in 2002.<\/p>\n<p dir=\"auto\">Shortly after, still in 2002, Joe starts writing his PhD thesis at the Swedish<br \/>\nInstitute of Computer Science (SICS). Joe was born 1950, so he was probably 52<br \/>\nyears old at this point. The topic of the thesis is <em>Making reliable distributed<br \/>\nsystems in the presence of software errors<\/em> and it was finished the year after<br \/>\nin 2003.<\/p>\n<p dir=\"auto\">It&#8217;s quite an unusual thesis in many ways. For starters, most theses are written<br \/>\nby people in their twenties with zero experience of practical applications.<br \/>\nWhereas in Joe&#8217;s case he has been working professionally on this topic since the<br \/>\n80s, i.e. about twenty years. The thesis contains no math nor theory, it&#8217;s<br \/>\nmerely a presentation of the ideas that underpin Erlang and how they used Erlang<br \/>\nto achieve the original goal of building reliable distributed systems.<\/p>\n<p dir=\"auto\">I highly commend reading his<br \/>\n<a href=\"http:\/\/kth.diva-portal.org\/smash\/record.jsf?pid=diva2%3A9492&#038;dswid=-1166\" rel=\"nofollow\">thesis<\/a><br \/>\nand forming your own opinion, but to me it&#8217;s clear that the big idea there isn&#8217;t<br \/>\nlightweight processes<sup><a href=\"http:\/\/github.com\/#user-content-fn-1-b236052c3934bd6f7ea3426445bf45af\" id=\"user-content-fnref-1-b236052c3934bd6f7ea3426445bf45af\" data-footnote-ref aria-describedby=\"footnote-label\">2<\/a><\/sup> and message passing, but rather the generic components<br \/>\nwhich in Erlang are called <em>behaviours<\/em>.<\/p>\n<h2 dir=\"auto\">Behaviours<\/h2>\n<p dir=\"auto\">I&#8217;ll first explain in more detail what behaviours are, and then I&#8217;ll come back<br \/>\nto the point that they are more important than the idea of lightweight processes.<\/p>\n<p dir=\"auto\">Erlang behaviours are like interfaces in, say, Java or Go. It&#8217;s a collection of<br \/>\ntype signatures which can have multiple implementations, and once the programmer<br \/>\nprovides such an implementation they get access to functions written against<br \/>\nthat interface. To make it more concrete here&#8217;s a contrived example in Go:<\/p>\n<div dir=\"auto\" data-snippet-clipboard-copy-content=\"\/\/ The interface.\ntype HasName interface {\n        Name() string\n}\n\n\/\/ A generic function written against the interface.\nfunc Greet(n HasName) {\n    fmt.Printf(\"Hello %s!n\", n.Name())\n}\n\n\/\/ First implementation of the interface.\ntype Joe struct {}\n\nfunc (_ *Joe) Name() string {\n        return \"Joe\"\n}\n\n\/\/ Second implementation of the interface.\ntype Mike struct {}\n\nfunc (_ *Mike) Name() string {\n        return \"Mike\"\n}\n\nfunc main() {\n        joe := &#038;Joe{}\n        mike := &#038;Mike{}\n        Greet(mike)\n        Greet(joe)\n}\"><\/p>\n<pre><span>\/\/ The interface.<\/span>\n<span>type<\/span> <span>HasName<\/span> <span>interface<\/span> {\n        <span>Name<\/span>() <span>string<\/span>\n}\n\n<span>\/\/ A generic function written against the interface.<\/span>\n<span>func<\/span> <span>Greet<\/span>(<span>n<\/span> <span>HasName<\/span>) {\n    <span>fmt<\/span>.<span>Printf<\/span>(<span>\"Hello %s!<span>n<\/span>\"<\/span>, <span>n<\/span>.<span>Name<\/span>())\n}\n\n<span>\/\/ First implementation of the interface.<\/span>\n<span>type<\/span> <span>Joe<\/span> <span>struct<\/span> {}\n\n<span>func<\/span> (<span>_<\/span> <span>*<\/span><span>Joe<\/span>) <span>Name<\/span>() <span>string<\/span> {\n        <span>return<\/span> <span>\"Joe\"<\/span>\n}\n\n<span>\/\/ Second implementation of the interface.<\/span>\n<span>type<\/span> <span>Mike<\/span> <span>struct<\/span> {}\n\n<span>func<\/span> (<span>_<\/span> <span>*<\/span><span>Mike<\/span>) <span>Name<\/span>() <span>string<\/span> {\n        <span>return<\/span> <span>\"Mike\"<\/span>\n}\n\n<span>func<\/span> <span>main<\/span>() {\n        <span>joe<\/span> <span>:=<\/span> <span>&<\/span><span>Joe<\/span>{}\n        <span>mike<\/span> <span>:=<\/span> <span>&<\/span><span>Mike<\/span>{}\n        <span>Greet<\/span>(<span>mike<\/span>)\n        <span>Greet<\/span>(<span>joe<\/span>)\n}<\/pre>\n<\/div>\n<p dir=\"auto\">Running the above program will display:<\/p>\n<p dir=\"auto\">This hopefully illustrates how <code>Greet<\/code> is generic in, or parametrised by, the<br \/>\ninterface <code>HasName<\/code>.<\/p>\n<h3 dir=\"auto\">Generic server behaviour<\/h3>\n<p dir=\"auto\">Next lets have look at a more complicated example in Erlang taken from Joe&#8217;s<br \/>\nthesis (p. 136). It&#8217;s a key-value store where we can <code>store<\/code> a key value pair or<br \/>\n<code>lookup<\/code> the value of a key, the <code>handle_call<\/code> part is the most interesting:<\/p>\n<div dir=\"auto\" data-snippet-clipboard-copy-content=\"-module(kv).\n-behaviour(gen_server).\n\n-export([start\/0, stop\/0, lookup\/1, store\/2]).\n\n-export([init\/1, handle_call\/3, handle_cast\/2, terminate\/2]).\n\nstart() -><br \/>\n  gen_server:start_link({local,kv},kv,arg1,[]).<\/p>\n<p>stop() -> gen_server:cast(kv, stop).<\/p>\n<p>init(arg1) -><br \/>\n  io:format(&#8220;Key-Value server starting~n&#8221;),<br \/>\n  {ok, dict:new()}.<\/p>\n<p>store(Key, Val) -><br \/>\n  gen_server:call(kv, {store, Key, Val}).<\/p>\n<p>lookup(Key) -> gen_server:call(kv, {lookup, Key}).<\/p>\n<p>handle_call({store, Key, Val}, From, Dict) -><br \/>\n  Dict1 = dict:store(Key, Val, Dict),<br \/>\n  {reply, ack, Dict1};<br \/>\nhandle_call({lookup, crash}, From, Dict) -><br \/>\n  1\/0; %% <- deliberate error :-)\nhandle_call({lookup, Key}, From, Dict) -><br \/>\n  {reply, dict:find(Key, Dict), Dict}.<\/p>\n<p>handle_cast(stop, Dict) -> {stop, normal, Dict}.<\/p>\n<p>terminate(Reason, Dict) -><br \/>\n  io:format(&#8220;K-V server terminating~n&#8221;).&#8221;><\/p>\n<pre>-<span>module<\/span>(<span>kv<\/span>).\n-<span>behaviour<\/span>(<span>gen_server<\/span>).\n\n-<span>export<\/span>([<span>start<\/span>\/<span>0<\/span>, <span>stop<\/span>\/<span>0<\/span>, <span>lookup<\/span>\/<span>1<\/span>, <span>store<\/span>\/<span>2<\/span>]).\n\n-<span>export<\/span>([<span>init<\/span>\/<span>1<\/span>, <span>handle_call<\/span>\/<span>3<\/span>, <span>handle_cast<\/span>\/<span>2<\/span>, <span>terminate<\/span>\/<span>2<\/span>]).\n\n<span>start<\/span>() <span>-><\/span>\n  <span>gen_server<\/span>:<span>start_link<\/span>({<span>local<\/span>,<span>kv<\/span>},<span>kv<\/span>,<span>arg1<\/span>,[]).\n\n<span>stop<\/span>() <span>-><\/span> <span>gen_server<\/span>:<span>cast<\/span>(<span>kv<\/span>, <span>stop<\/span>).\n\n<span>init<\/span>(<span>arg1<\/span>) <span>-><\/span>\n  <span>io<\/span>:<span>format<\/span>(<span><span>\"<\/span>Key-Value server starting<span>~n<\/span><span>\"<\/span><\/span>),\n  {<span>ok<\/span>, <span>dict<\/span>:<span>new<\/span>()}.\n\n<span>store<\/span>(<span>Key<\/span>, <span>Val<\/span>) <span>-><\/span>\n  <span>gen_server<\/span>:<span>call<\/span>(<span>kv<\/span>, {<span>store<\/span>, <span>Key<\/span>, <span>Val<\/span>}).\n\n<span>lookup<\/span>(<span>Key<\/span>) <span>-><\/span> <span>gen_server<\/span>:<span>call<\/span>(<span>kv<\/span>, {<span>lookup<\/span>, <span>Key<\/span>}).\n\n<span>handle_call<\/span>({<span>store<\/span>, <span>Key<\/span>, <span>Val<\/span>}, <span>From<\/span>, <span>Dict<\/span>) <span>-><\/span>\n  <span>Dict1<\/span> <span>=<\/span> <span>dict<\/span>:<span>store<\/span>(<span>Key<\/span>, <span>Val<\/span>, <span>Dict<\/span>),\n  {<span>reply<\/span>, <span>ack<\/span>, <span>Dict1<\/span>};\n<span>handle_call<\/span>({<span>lookup<\/span>, <span>crash<\/span>}, <span>From<\/span>, <span>Dict<\/span>) <span>-><\/span>\n  <span>1<\/span><span>\/<\/span><span>0<\/span>; <span><span>%<\/span>% <- deliberate error :-)<\/span>\n<span>handle_call<\/span>({<span>lookup<\/span>, <span>Key<\/span>}, <span>From<\/span>, <span>Dict<\/span>) <span>-><\/span>\n  {<span>reply<\/span>, <span>dict<\/span>:<span>find<\/span>(<span>Key<\/span>, <span>Dict<\/span>), <span>Dict<\/span>}.\n\n<span>handle_cast<\/span>(<span>stop<\/span>, <span>Dict<\/span>) <span>-><\/span> {<span>stop<\/span>, <span>normal<\/span>, <span>Dict<\/span>}.\n\n<span>terminate<\/span>(<span>Reason<\/span>, <span>Dict<\/span>) <span>-><\/span>\n  <span>io<\/span>:<span>format<\/span>(<span><span>\"<\/span>K-V server terminating<span>~n<\/span><span>\"<\/span><\/span>).<\/pre>\n<\/div>\n<p dir=\"auto\">This is an implementation of the <code>gen_server<\/code> behaviour\/interface. Notice how<br \/>\n<code>handle_call<\/code> updates the state (<code>Dict<\/code>) in case of a <code>store<\/code> and <code>lookup<\/code>s the<br \/>\nkey in the state. Once <code>gen_server<\/code> is given this implementation it will provide<br \/>\na server which can handle concurrent <code>store<\/code> and <code>lookup<\/code> requests, similarly to<br \/>\nhow <code>Greet<\/code> provided the displaying functionality.<\/p>\n<p dir=\"auto\">At this point you might be thinking &#8220;OK, so what? Lots of programming languages<br \/>\nhave interfaces&#8230;&#8221;. That&#8217;s true, but notice how <code>handle_call<\/code> is completely<br \/>\nsequential, i.e. all concurrency is hidden away in the generic <code>gen_server<\/code><br \/>\ncomponent. &#8220;Yeah, but that&#8217;s just good engineering practice which can be done in<br \/>\nany language&#8221; you say. That&#8217;s true as well, but the thesis pushes this idea<br \/>\nquite far. It identifies six behaviours: <code>gen_server<\/code>, <code>gen_event<\/code>, <code>gen_fsm<\/code>,<br \/>\n<code>supervisor<\/code>, <code>application<\/code>, and <code>release<\/code> and then says these are enough to<br \/>\nbuild reliable distributed systems. As a case study Joe uses one of Ericsson&#8217;s<br \/>\ntelephone switches (p. 157):<\/p>\n<blockquote>\n<p dir=\"auto\">When we look at the AXD301 project in chapter 8, we will see that there were<br \/>\n122 instances of gen_server, 36 instances of gen_event and 10 instances of<br \/>\ngen_fsm. There were 20 supervisors and 6 applications. All this is packaged<br \/>\ninto one release.<\/p>\n<\/blockquote>\n<p dir=\"auto\">Joe gives several arguments for why behaviour should be used (p. 157-158):<\/p>\n<ol dir=\"auto\">\n<li>\n<p dir=\"auto\">The application programmer only has to provide the part of the code which<br \/>\ndefines the <em>semantics<\/em> (or &#8220;business logic&#8221;) of their problem, while the<br \/>\n<em>infrastructure<\/em> code is provided automatically by the behaviour;<\/p>\n<\/li>\n<li>\n<p dir=\"auto\">The application programmer writes sequential code, all concurrency is hidden<br \/>\naway in the behaviour;<\/p>\n<\/li>\n<li>\n<p dir=\"auto\">Behaviours are written by experts, and based on years of experience and<br \/>\nrepresent &#8220;best practices&#8221;;<\/p>\n<\/li>\n<li>\n<p dir=\"auto\">Easier for new team members to get started: business logic is sequential,<br \/>\nsimilar structure that they might have seen before elsewhere;<\/p>\n<\/li>\n<li>\n<p dir=\"auto\">If whole systems are implemented reusing a small set of behaviours: as<br \/>\nbehaviour implementations improve the whole systems will improve without<br \/>\nrequiring any code changes;<\/p>\n<\/li>\n<li>\n<p dir=\"auto\">Sticking to only using behaviours enforces structure, which in turn makes<br \/>\ntesting and formal verification much easier.<\/p>\n<\/li>\n<\/ol>\n<p dir=\"auto\">We&#8217;ll come back to this last point about testing later.<\/p>\n<h3 dir=\"auto\">Event manager behaviour<\/h3>\n<p dir=\"auto\">Lets come back to the behaviours we listed above first. We looked at<br \/>\n<code>gen_server<\/code>, but what are the others for? There&#8217;s <code>gen_event<\/code> which is a<br \/>\ngeneric event manager, which lets you register event handlers that are then run<br \/>\nwhen the event manager gets messages associated with the handlers. Joe says this<br \/>\nis useful for, e.g., error logging and gives the following example of an simple<br \/>\nlogger (p. 142):<\/p>\n<div dir=\"auto\" data-snippet-clipboard-copy-content=\"-module(simple_logger).\n-behaviour(gen_event).\n\n-export([start\/0, stop\/0, log\/1, report\/0]).\n\n-export([init\/1, terminate\/2,\n         handle_event\/2, handle_call\/2]).\n\n-define(NAME, my_simple_event_logger).\n\nstart() -><br \/>\n  case gen_event:start_link({local, ?NAME}) of<br \/>\n    Ret = {ok, Pid} -><br \/>\n      gen_event:add_handler(?NAME,?MODULE,arg1),<br \/>\n      Ret;<br \/>\n  Other -><br \/>\n    Other<br \/>\n  end.<\/p>\n<p>stop() -> gen_event:stop(?NAME).<\/p>\n<p>log(E) -> gen_event:notify(?NAME, {log, E}).<\/p>\n<p>report() -><br \/>\n  gen_event:call(?NAME, ?MODULE, report).<\/p>\n<p>init(arg1) -><br \/>\n  io:format(&#8220;Logger starting~n&#8221;),<br \/>\n  {ok, []}.<\/p>\n<p>handle_event({log, E}, S) -> {ok, trim([E|S])}.<\/p>\n<p>handle_call(report, S) -> {ok, S, S}.<\/p>\n<p>terminate(stop, _) -> true.<\/p>\n<p>trim([X1,X2,X3,X4,X5|_]) -> [X1,X2,X3,X4,X5];<br \/>\ntrim(L) -> L.&#8221;><\/p>\n<pre>-<span>module<\/span>(<span>simple_logger<\/span>).\n-<span>behaviour<\/span>(<span>gen_event<\/span>).\n\n-<span>export<\/span>([<span>start<\/span>\/<span>0<\/span>, <span>stop<\/span>\/<span>0<\/span>, <span>log<\/span>\/<span>1<\/span>, <span>report<\/span>\/<span>0<\/span>]).\n\n-<span>export<\/span>([<span>init<\/span>\/<span>1<\/span>, <span>terminate<\/span>\/<span>2<\/span>,\n         <span>handle_event<\/span>\/<span>2<\/span>, <span>handle_call<\/span>\/<span>2<\/span>]).\n\n-<span>define<\/span>(<span>NAME<\/span>, <span>my_simple_event_logger<\/span>).\n\n<span>start<\/span>() <span>-><\/span>\n  <span>case<\/span> <span>gen_event<\/span>:<span>start_link<\/span>({<span>local<\/span>, <span>?<\/span><span>NAME<\/span>}) <span>of<\/span>\n    <span>Ret<\/span> <span>=<\/span> {<span>ok<\/span>, <span>Pid<\/span>} ->\n      <span>gen_event<\/span>:<span>add_handler<\/span>(<span>?<\/span><span>NAME<\/span>,<span>?<\/span><span>MODULE<\/span>,<span>arg1<\/span>),\n      <span>Ret<\/span>;\n  <span>Other<\/span> ->\n    <span>Other<\/span>\n  <span>end<\/span>.\n\n<span>stop<\/span>() <span>-><\/span> <span>gen_event<\/span>:<span>stop<\/span>(<span>?<\/span><span>NAME<\/span>).\n\n<span>log<\/span>(<span>E<\/span>) <span>-><\/span> <span>gen_event<\/span>:<span>notify<\/span>(<span>?<\/span><span>NAME<\/span>, {<span>log<\/span>, <span>E<\/span>}).\n\n<span>report<\/span>() <span>-><\/span>\n  <span>gen_event<\/span>:<span>call<\/span>(<span>?<\/span><span>NAME<\/span>, <span>?<\/span><span>MODULE<\/span>, <span>report<\/span>).\n\n<span>init<\/span>(<span>arg1<\/span>) <span>-><\/span>\n  <span>io<\/span>:<span>format<\/span>(<span><span>\"<\/span>Logger starting<span>~n<\/span><span>\"<\/span><\/span>),\n  {<span>ok<\/span>, []}.\n\n<span>handle_event<\/span>({<span>log<\/span>, <span>E<\/span>}, <span>S<\/span>) <span>-><\/span> {<span>ok<\/span>, <span>trim<\/span>([<span>E<\/span>|<span>S<\/span>])}.\n\n<span>handle_call<\/span>(<span>report<\/span>, <span>S<\/span>) <span>-><\/span> {<span>ok<\/span>, <span>S<\/span>, <span>S<\/span>}.\n\n<span>terminate<\/span>(<span>stop<\/span>, <span>_<\/span>) <span>-><\/span> <span>true<\/span>.\n\n<span>trim<\/span>([<span>X1<\/span>,<span>X2<\/span>,<span>X3<\/span>,<span>X4<\/span>,<span>X5<\/span>|<span>_<\/span>]) <span>-><\/span> [<span>X1<\/span>,<span>X2<\/span>,<span>X3<\/span>,<span>X4<\/span>,<span>X5<\/span>];\n<span>trim<\/span>(<span>L<\/span>) <span>-><\/span> <span>L<\/span>.<\/pre>\n<\/div>\n<p dir=\"auto\">The interesting part is <code>handle_event<\/code>, <code>trim<\/code> and <code>report<\/code>. Together they let<br \/>\nthe user log, keep track and display the last five error messages.<\/p>\n<h3 dir=\"auto\">State machine behaviour<\/h3>\n<p dir=\"auto\">The <code>gen_fsm<\/code> behavior has been renamed to <code>gen_statem<\/code> (for state machine)<br \/>\nsince thesis was written. It&#8217;s very similar to <code>gen_server<\/code>, but more geared<br \/>\ntowards implementing protocols, which often are specified as state machines. I<br \/>\nbelieve any <code>gen_server<\/code> can be implemented as a <code>gen_statem<\/code> and vice versa so<br \/>\nwe won&#8217;t go into the details of <code>gen_statem<\/code>.<\/p>\n<h3 dir=\"auto\">Supervisor behaviour<\/h3>\n<p dir=\"auto\">The next interesting behavior is <code>supervisor<\/code>. Supervisors are processes which<br \/>\nsole job is to make sure that other processes are healthy and doing their job.<br \/>\nIf a supervised process fails then the supervisor can restart it according<br \/>\nto some predefined strategy. Here&#8217;s an example due to Joe (p. 148):<\/p>\n<div dir=\"auto\" data-snippet-clipboard-copy-content=\"-module(simple_sup).\n-behaviour(supervisor).\n\n-export([start\/0, init\/1]).\n\nstart() -><br \/>\n  supervisor:start_link({local, simple_supervisor},<br \/>\n  ?MODULE, nil).<\/p>\n<p>init(_) -><br \/>\n  {ok,<br \/>\n  {{one_for_one, 5, 1000},<br \/>\n  [<br \/>\n   {packet,<br \/>\n     {packet_assembler, start, []},<br \/>\n     permanent, 500, worker, [packet_assembler]},<br \/>\n   {server,<br \/>\n     {kv, start, []},<br \/>\n     permanent, 500, worker, [kv]},<br \/>\n   {logger,<br \/>\n     {simple_logger, start, []},<br \/>\n     permanent, 500, worker, [simple_logger]}]}}.&#8221;><\/p>\n<pre>-<span>module<\/span>(<span>simple_sup<\/span>).\n-<span>behaviour<\/span>(<span>supervisor<\/span>).\n\n-<span>export<\/span>([<span>start<\/span>\/<span>0<\/span>, <span>init<\/span>\/<span>1<\/span>]).\n\n<span>start<\/span>() <span>-><\/span>\n  <span>supervisor<\/span>:<span>start_link<\/span>({<span>local<\/span>, <span>simple_supervisor<\/span>},\n  <span>?<\/span><span>MODULE<\/span>, <span>nil<\/span>).\n\n<span>init<\/span>(<span>_<\/span>) <span>-><\/span>\n  {<span>ok<\/span>,\n  {{<span>one_for_one<\/span>, <span>5<\/span>, <span>1000<\/span>},\n  [\n   {<span>packet<\/span>,\n     {<span>packet_assembler<\/span>, <span>start<\/span>, []},\n     <span>permanent<\/span>, <span>500<\/span>, <span>worker<\/span>, [<span>packet_assembler<\/span>]},\n   {<span>server<\/span>,\n     {<span>kv<\/span>, <span>start<\/span>, []},\n     <span>permanent<\/span>, <span>500<\/span>, <span>worker<\/span>, [<span>kv<\/span>]},\n   {<span>logger<\/span>,\n     {<span>simple_logger<\/span>, <span>start<\/span>, []},\n     <span>permanent<\/span>, <span>500<\/span>, <span>worker<\/span>, [<span>simple_logger<\/span>]}]}}.<\/pre>\n<\/div>\n<p dir=\"auto\">The <code>{one_for_one, 5, 1000}<\/code> is the restart strategy. It says that if one of the<br \/>\nsupervised processes (<code>packet_assembler<\/code>, <code>kv<\/code>, and <code>simple_logger<\/code>) fail then<br \/>\nonly restart the failing process (<code>one_for_one<\/code>). If the supervisor needs to<br \/>\nrestart more than <code>5<\/code> times in <code>1000<\/code> seconds then the supervisor itself should<br \/>\nfail.<\/p>\n<p dir=\"auto\">The <code>permanent, 500, worker<\/code> part means that this is a worker process which<br \/>\nshould be permanently kept alive and its given 500 milliseconds to gracefully<br \/>\nstop what it&#8217;s doing in case the supervisor wants to restart it.<\/p>\n<p dir=\"auto\">&#8220;Why would the supervisor want to restart it if it&#8217;s not dead already?&#8221;, one<br \/>\nmight wonder. Well, there are other restart strategies than <code>one_for_one<\/code>. For<br \/>\nexample, <code>one_for_all<\/code> where if one process fails then the supervisor restarts<br \/>\nall of its children.<\/p>\n<p dir=\"auto\">If we also consider that supervisors can supervise supervisors, which are not<br \/>\nnecessarily running on the same computer, then I hope that you get an idea of<br \/>\npowerful this behaviour can be. And, no, this isn&#8217;t &#8220;just Kubernetes&#8221;, because<br \/>\nit&#8217;s at the thread\/lightweight process level rather than docker container level.<\/p>\n<p dir=\"auto\">The idea for supervisors and their restart strategies comes from the observation<br \/>\nthat often a restart appears to fix the problem, as captured in the <em>Have You<br \/>\nTried Turning It Off And On Again?<\/em> sketches from IT Crowd.<\/p>\n<p dir=\"auto\">Knowing that failing processes will get restarted coupled with Jim Gray&#8217;s idea<br \/>\nof failing fast, that&#8217;s either produce the output according to the specification<br \/>\nor signal failure and stop operating, leads to Joe&#8217;s slogan: &#8220;Let it crash!&#8221; (p.<br \/>\n107). Another way to think of it is that a program should only express its<br \/>\n&#8220;happy path&#8221;, should anything go wrong on its happy way it should crash, rather<br \/>\nthan trying to be clever about it and try to fix the problem (potentially making<br \/>\nit worse), and another program higher up the supervisor tree will handle it.<\/p>\n<p dir=\"auto\">Supervisors and the &#8220;let it crash&#8221; philosophy, appear to produce reliable<br \/>\nsystems. Joe uses the Ericsson AXD301 telephone switch example again (p. 191):<\/p>\n<blockquote>\n<p dir=\"auto\">Evidence for the long-term operational stability of the system had also not<br \/>\nbeen collected in any systematic way. For the Ericsson AXD301 the only<br \/>\ninformation on the long-term stability of the system came from a power-point<br \/>\npresentation showing some figures claiming that a major customer had run an 11<br \/>\nnode system with a 99.9999999% reliability, though how these figure had been<br \/>\nobtained was not documented.<\/p>\n<\/blockquote>\n<p dir=\"auto\">To put this in perspective, five nines (99.999%) reliability is considered good<br \/>\n(5.26 minutes of downtime per year). &#8220;59% of Fortune 500 companies experience a<br \/>\nminimum of 1.6 hours of downtime per week&#8221;, according to some<br \/>\n<a href=\"https:\/\/courseware.cutm.ac.in\/wp-content\/uploads\/2020\/06\/Assessing-the-Financial-Impact-of-Downtime-UK.pdf\" rel=\"nofollow\">report<\/a><br \/>\nfrom a biased company. Notice per <em>year<\/em> vs per <em>week<\/em>, but as we don&#8217;t know how<br \/>\neither reliability numbers are obtained its probably safe to assume that the<br \/>\ntruth is somewhere in the middle &#8212; still a big difference, but not 31.56<br \/>\nmilliseconds (nine nines) of downtime per year vs 1.6 hours of downtime per<br \/>\nweek.<\/p>\n<h3 dir=\"auto\">Application and release behaviours<\/h3>\n<p dir=\"auto\">I&#8217;m not sure if <code>application<\/code> and <code>release<\/code> technically are behaviours, i.e.<br \/>\ninterfaces. They are part of the same chapter as the other behaviours in the<br \/>\nthesis and they do provide a clear structure which is a trait of the other<br \/>\nbehaviours though, so we&#8217;ll include them in the discussion.<\/p>\n<p dir=\"auto\">So far we&#8217;ve presented behaviours from the bottom up. We started with &#8220;worker&#8221;<br \/>\nbehaviours <code>gen_server<\/code>, <code>gen_statem<\/code> and <code>gen_event<\/code> which together capture the<br \/>\nsemantics of our problem. We then saw how we can define <code>supervisor<\/code> trees whose<br \/>\nchildren are other supervisor trees or workers, to deal with failures and<br \/>\nrestarts.<\/p>\n<p dir=\"auto\">Next level up is an <code>application<\/code> which consists of a supervisor tree together<br \/>\nwith everything else we need to deliver a particular application.<\/p>\n<p dir=\"auto\">A system can consist of several <code>application<\/code> and that&#8217;s where the final<br \/>\n&#8220;behaviour&#8221; comes in. A <code>release<\/code> packages up one or more applications. They<br \/>\nalso contain code to handle upgrades. If the upgrade fails, it must be able to<br \/>\nrollback to the previous stable state.<\/p>\n<h2 dir=\"auto\">How behaviours can be implemented<\/h2>\n<p dir=\"auto\">I hope that by now I&#8217;m managed to convince you that it&#8217;s not actually the<br \/>\nlightweight processes and message passing by themselves that make Erlang great<br \/>\nfor building reliable systems.<\/p>\n<p dir=\"auto\">At best one might be able to claim that lightweight processes and supervisors<br \/>\nare the key mechanisms at play<sup><a href=\"http:\/\/github.com\/#user-content-fn-2-b236052c3934bd6f7ea3426445bf45af\" id=\"user-content-fnref-2-b236052c3934bd6f7ea3426445bf45af\" data-footnote-ref aria-describedby=\"footnote-label\">3<\/a><\/sup>, but I think it would be more honest to recognise<br \/>\nthe structure that behaviours provide and how that ultimately leads to reliable<br \/>\nsoftware.<\/p>\n<p dir=\"auto\">I&#8217;ve not come across any other language, library, or framework which provides<br \/>\nsuch relatively simple building blocks that compose into big systems like the<br \/>\nAXD301 (&#8220;over a million lines of Erlang code&#8221;, p. 167).<\/p>\n<p dir=\"auto\">This begs the question: why aren&#8217;t language and library designers stealing the<br \/>\nstructure behind Erlang&#8217;s behaviours, rather than copying the ideas of<br \/>\nlightweight processes and message passing?<\/p>\n<p dir=\"auto\">Let&#8217;s take a step back. We said earlier that behaviours are interfaces and many<br \/>\nprogramming languages have interfaces. How would we go about starting to<br \/>\nimplement behaviours in other languages?<\/p>\n<p dir=\"auto\">Lets start with <code>gen_server<\/code>. I like to think its interface signature as being:<\/p>\n<div dir=\"auto\" data-snippet-clipboard-copy-content=\"Input -> State -> (State, Output)&#8221;><\/p>\n<pre><span>Input<\/span> <span>-><\/span> <span>State<\/span> <span>-><\/span> (<span>State<\/span>, <span>Output<\/span>)<\/pre>\n<\/div>\n<p dir=\"auto\">That&#8217;s it takes some input, its current state and produces a pair of the new<br \/>\nupdated state and an output.<\/p>\n<p dir=\"auto\">How do we turn this sequential signature into something that can handle<br \/>\nconcurrent requests? One way would be to fire up a HTTP server which transforms<br \/>\nrequests into <code>Input<\/code>s and puts them on a queue, have an event loop which pops<br \/>\ninputs from the queue and feeds it to the sequential implementation, then<br \/>\nwriting the output back to the client response. It wouldn&#8217;t be difficult to<br \/>\ngeneralise this to be able to handle multiple <code>gen_server<\/code>s at the same time, by<br \/>\ngiving each a name and let the request include the name in addition to the<br \/>\ninput.<\/p>\n<p dir=\"auto\"><code>gen_event<\/code> could be implemented by allowing registration of callbacks to<br \/>\ncertain types of event on the queue.<\/p>\n<p dir=\"auto\"><code>supervisor<\/code>s is more interesting, one simple way to think of it is: when we<br \/>\nfeed the <code>gen_server<\/code> function the next input from the queue, we wrap that call<br \/>\nin an exception handler, and should it throw we notify its supervisor. It gets a<br \/>\nbit more complicated if the supervisor is not running on the same computer as<br \/>\nthe <code>gen_server<\/code>.<\/p>\n<p dir=\"auto\">I haven&#8217;t thought about <code>application<\/code> and <code>release<\/code>s much yet, but given that<br \/>\nconfiguration, deployment and upgrades are difficult problems they seem<br \/>\nimportant.<\/p>\n<h2 dir=\"auto\">Correctness of behaviours<\/h2>\n<p dir=\"auto\">Writing a post solely about stealing from Erlang doesn&#8217;t seem fair, even though<br \/>\nit&#8217;s the right thing to do, so I&#8217;d like to finish off with how we can build upon<br \/>\nthe insights of Joe and the Erlang community.<\/p>\n<p dir=\"auto\">I&#8217;ve been interesting in testing for a while now. Most recently I&#8217;ve been<br \/>\nlooking into <a href=\"https:\/\/github.com\/stevana\/property-based-testing-stateful-systems-tutorial\">simulation<br \/>\ntesting<\/a><br \/>\ndistributed systems \u00e0 la<br \/>\n<a href=\"https:\/\/www.youtube.com\/watch?v=4fFDFbi3toc\" rel=\"nofollow\">FoundationDB<\/a>.<\/p>\n<p dir=\"auto\">Simulation testing in a nutshell is running your system in a simulated world,<br \/>\nwhere the simulation has full control over which messages get sent when over the<br \/>\nnetwork.<\/p>\n<p dir=\"auto\">FoundationDB built their own programming language, or dialect of C++ with<br \/>\nactors, in order do the simulation testing. Our team seemed to be able to get<br \/>\nquite far with merely using state machines of type:<\/p>\n<div dir=\"auto\" data-snippet-clipboard-copy-content=\"Input -> State -> (State, [Output])&#8221;><\/p>\n<pre><span>Input<\/span> <span>-><\/span> <span>State<\/span> <span>-><\/span> (<span>State<\/span>, [<span>Output<\/span>])<\/pre>\n<\/div>\n<p dir=\"auto\">where <code>[Output]<\/code> is a sequence of outputs.<\/p>\n<p dir=\"auto\">The idea being that the simulator keeps track of a priority queue of messages<br \/>\nsorted by their arrival time, it pops a message, advances the clock to the<br \/>\narrival time of that message, feeds the message to the receiving state machine,<br \/>\ngenerates new arrival times for all output messages and puts them back into the<br \/>\npriority queue, rinse and repeat. As long as everything is deterministic and the<br \/>\narrival times are generated using a seed we can explore many different<br \/>\ninterleavings and get reproducible failures. It&#8217;s also much faster than Jepsen,<br \/>\nbecause messaging is done in-memory and we advance the clock to the arrival<br \/>\ntime, thereby triggering any timeouts without having to wait for them.<\/p>\n<p dir=\"auto\">We used to say that programs of this state machine type where written in<br \/>\n&#8220;network normal form&#8221;, and conjectured that every program which can receive and<br \/>\nsend stuff over the network can be refactored into this shape<sup><a href=\"http:\/\/github.com\/#user-content-fn-3-b236052c3934bd6f7ea3426445bf45af\" id=\"user-content-fnref-3-b236052c3934bd6f7ea3426445bf45af\" data-footnote-ref aria-describedby=\"footnote-label\">4<\/a><\/sup>. Even if we<br \/>\nhad a proof, &#8220;network normal form&#8221; always felt a bit arbitrary. But then I read<br \/>\nJoe&#8217;s thesis and realised that <code>gen_server<\/code> and <code>gen_statem<\/code> basically have the<br \/>\nsame type, so I stopped being concerned about it. As I think that if a structure<br \/>\nis found to be useful by different people, then it&#8217;s usually a sign that it<br \/>\nisn&#8217;t arbitrary.<\/p>\n<p dir=\"auto\">Anyway, in, at least, one of Joe&#8217;s <a href=\"https:\/\/youtu.be\/cNICGEwmXLU?t=1439\" rel=\"nofollow\">talks<\/a><br \/>\nhe mentions how difficult it&#8217;s to correctly implement distributed leader<br \/>\nelection.<\/p>\n<p dir=\"auto\">I believe this is a problem that would be greatly simplified by having access to<br \/>\na simulator. A bit like I&#8217;d imagine having access to a wind tunnel would make<br \/>\nbuilding an airplane easier. Both lets you test your system under extreme<br \/>\nconditions, such as unreliable networking or power loss, before they happen in<br \/>\n&#8220;production&#8221;. Furthermore, this simulator can be generic in, or parametrised by,<br \/>\nbehaviours. Which means that the developer gets it for free while the complexity<br \/>\nof the simulator is hidden away, just like the concurrent code of <code>gen_server<\/code>!<\/p>\n<p dir=\"auto\">FoundationDB is a good example of simulation testing working, as witnessed by<br \/>\nthis <a href=\"https:\/\/twitter.com\/aphyr\/status\/405017101804396546\" rel=\"nofollow\">tweet<\/a> where somebody<br \/>\nasked Kyle &#8220;aphyr&#8221; Kingsbury to Jepsen test FoundationDB:<\/p>\n<blockquote>\n<p dir=\"auto\">\u201chaven\u2019t tested foundation[db] in part because their testing appears to be<br \/>\nwaaaay more rigorous than mine.\u201d<\/p>\n<\/blockquote>\n<p dir=\"auto\">Formal verification is also made easier if the program is written a state<br \/>\nmachine. Basically all of Lamport&#8217;s model checking<br \/>\n<a href=\"https:\/\/www.microsoft.com\/en-us\/research\/publication\/computation-state-machines\/\" rel=\"nofollow\">work<\/a><br \/>\nwith TLA+ assumes that the specification is a state machine. Also more recently<br \/>\nKleppmann has<br \/>\n<a href=\"https:\/\/lawrencecpaulson.github.io\/2022\/10\/12\/verifying-distributed-systems-isabelle.html\" rel=\"nofollow\">shown<\/a><br \/>\nhow to exploit the state machine structure to do proof by (structural) induction<br \/>\nto solve the state explosion problem.<\/p>\n<p dir=\"auto\">So there you have it, we&#8217;ve gone full circle. We started by taking inspiration<br \/>\nfrom Joe and Erlang&#8217;s behaviours, and ended up using the structure of the<br \/>\n<code>gen_server<\/code> behaviour to make it easier to solve a problem that Joe used to<br \/>\nhave.<\/p>\n<h2 dir=\"auto\">Contributing<\/h2>\n<p dir=\"auto\">There are a bunch of related ideas that I have started working on:<\/p>\n<ul dir=\"auto\">\n<li>Stealing ideas from Martin Thompson&#8217;s work on the LMAX Disruptor and<br \/>\n<a href=\"https:\/\/github.com\/real-logic\/aeron\">aeron<\/a> to make a fast event loop, on<br \/>\ntop of which the behaviours run;<\/li>\n<li>Enriching the state machine type with <a href=\"https:\/\/github.com\/stevana\/coroutine-state-machines\">async<br \/>\nI\/O<\/a>;<\/li>\n<li>How to implement supervisors in more detail;<\/li>\n<li>Hot code swapping of state machines.<\/li>\n<\/ul>\n<p dir=\"auto\">I hope to write about these things separately at some later point.<\/p>\n<p dir=\"auto\">Meanwhile feel free to get in touch, if you find any of this interesting and<br \/>\nwould like to get involved, or if you have have comments, suggestions or<br \/>\nquestions.<\/p>\n<h2 dir=\"auto\">See also<\/h2>\n<ul dir=\"auto\">\n<li>Chapter 6.1 on behaviours in Joe Armstrong&#8217;s<br \/>\n<a href=\"http:\/\/kth.diva-portal.org\/smash\/record.jsf?pid=diva2%3A9492&#038;dswid=-1166\" rel=\"nofollow\">thesis<\/a>,<br \/>\np. 129;<\/li>\n<li><a href=\"https:\/\/www.erlang.org\/doc\/design_principles\/des_princ.html\" rel=\"nofollow\">OTP design principles<\/a>;<\/li>\n<li>The documentation for behaviours:\n<ul dir=\"auto\">\n<li><a href=\"https:\/\/www.erlang.org\/doc\/man\/gen_server.html\" rel=\"nofollow\"><code>gen_server<\/code><\/a>;<\/li>\n<li><a href=\"https:\/\/www.erlang.org\/doc\/man\/gen_event.html\" rel=\"nofollow\"><code>gen_event<\/code><\/a>;<\/li>\n<li><a href=\"https:\/\/www.erlang.org\/doc\/man\/gen_statem.html\" rel=\"nofollow\"><code>gen_statem<\/code><\/a>;<\/li>\n<li><a href=\"https:\/\/www.erlang.org\/doc\/man\/supervisor.html\" rel=\"nofollow\"><code>supervisor<\/code><\/a>;<\/li>\n<li><a href=\"https:\/\/www.erlang.org\/doc\/man\/application.html\" rel=\"nofollow\"><code>application<\/code><\/a>;<\/li>\n<li><a href=\"https:\/\/www.erlang.org\/doc\/design_principles\/release_structure.html\" rel=\"nofollow\">release<\/a>.<\/li>\n<\/ul>\n<\/li>\n<li><a href=\"https:\/\/youtube.com\/watch?v=7erJ1DV_Tlo\" rel=\"nofollow\">Hewitt, Meijer and Szyperski: The Actor Model (everything you wanted to know,<br \/>\nbut were afraid to ask)<\/a> (2012);<\/li>\n<li>Erlang the <a href=\"https:\/\/www.youtube.com\/watch?v=xrIjfIjssLE\" rel=\"nofollow\">movie<\/a> (1990);<\/li>\n<li><a href=\"https:\/\/www.youtube.com\/watch?v=cNICGEwmXLU\" rel=\"nofollow\">Systems that run forever self-heal and<br \/>\nscale<\/a> by Joe Armstrong (Strange<br \/>\nLoop, 2013);<\/li>\n<li><a href=\"https:\/\/www.youtube.com\/watch?v=TTM_b7EJg5E\" rel=\"nofollow\">The Do&#8217;s and Don&#8217;ts of Error<br \/>\nHandling<\/a> by Joe Armstrong (GOTO,<br \/>\n2018);<\/li>\n<li><a href=\"https:\/\/ferd.ca\/the-zen-of-erlang.html\" rel=\"nofollow\">The Zen of Erlang<\/a> by Fred Hebert<br \/>\n(2016);<\/li>\n<li><a href=\"https:\/\/ferd.ca\/the-hitchhiker-s-guide-to-the-unexpected.html\" rel=\"nofollow\">The Hitchhiker&#8217;s Guide to the<br \/>\nUnexpected<\/a> by<br \/>\nFred Hebert (2018);<\/li>\n<li><a href=\"https:\/\/www.hpl.hp.com\/techreports\/tandem\/TR-85.7.pdf\" rel=\"nofollow\">Why Do Computers Stop and What Can Be Done About<br \/>\nIt?<\/a> by Jim Gray<br \/>\n(1985);<\/li>\n<li>The supervision trees chapter of <a href=\"https:\/\/adoptingerlang.org\/docs\/development\/supervision_trees\/\" rel=\"nofollow\"><em>Adopting<br \/>\nErlang<\/em><\/a><br \/>\n(2019);<\/li>\n<li>&#8220;If there&#8217;s one thing I&#8217;d say to the Erlang folks, it&#8217;s you got the stuff<br \/>\nright from a high-level, but you need to invest in your messaging<br \/>\ninfrastructure so it&#8217;s super fast, super efficient and obeys all the right<br \/>\nproperties to let this stuff work really well.&#8221;<br \/>\n<a href=\"https:\/\/youtu.be\/OqsAGFExFgQ?t=2532\" rel=\"nofollow\">quote<\/a> by Martin Thompson (Functional<br \/>\nConf, 2017).<\/li>\n<\/ul>\n<section data-footnotes>\n<ol dir=\"auto\">\n<li id=\"user-content-fn-0-b236052c3934bd6f7ea3426445bf45af\">\n<p dir=\"auto\">From Joe Armstrong&#8217;s thesis (p. 6):<\/p>\n<blockquote>\n<p dir=\"auto\">In February 1998 Erlang was banned for new product development within<br \/>\nEricsson\u2014the main reason for the ban was that Ericsson wanted to be a consumer<br \/>\nof sodware technologies rather than a producer.<\/p>\n<\/blockquote>\n<p dir=\"auto\">From Bjarne D\u00e4cker&#8217;s thesis (2000, p. 37):<\/p>\n<blockquote>\n<p dir=\"auto\">In February 1998, Erlang was banned within Ericsson Radio AB (ERA) for new<br \/>\nproduct projects aimed for external customers because:<\/p>\n<p dir=\"auto\">\u201cThe selection of an implementation language implies a more long-term<br \/>\ncommitment than selection of processors and OS, due to the longer life cycle<br \/>\nof implemented products. Use of a proprietary language, implies a continued<br \/>\neffort to maintain and further develop the support and the development<br \/>\nenvironment. It further implies that we cannot easily benefit from, and find<br \/>\nsynergy with, the evolution following the large scale deployment of globally<br \/>\nused languages.\u201d<\/p>\n<\/blockquote>\n<p><a href=\"http:\/\/github.com\/#user-content-fnref-0-b236052c3934bd6f7ea3426445bf45af\" data-footnote-backref aria-label=\"Back to content\"><g-emoji alias=\"leftwards_arrow_with_hook\" fallback-src=\"https:\/\/github.githubassets.com\/images\/icons\/emoji\/unicode\/21a9.png\">\u21a9<\/g-emoji><\/a>\n<\/li>\n<li id=\"user-content-fn-1-b236052c3934bd6f7ea3426445bf45af\">\n<p dir=\"auto\">It&#8217;s a common misconception is that Erlang is about actors.<\/p>\n<p dir=\"auto\">The actor model first presented in <a href=\"https:\/\/www.ijcai.org\/Proceedings\/73\/Papers\/027B.pdf\"><em>A Universal Modular Actor Formalism for<br \/>\nArtificial<br \/>\nIntelligence<\/em><\/a> by Carl<br \/>\nHewitt, Peter Bishop, Richard Steiger (1973) and refined by others over time,<br \/>\ne.g. see Irene Greif&#8217;s <a href=\"https:\/\/dspace.mit.edu\/handle\/1721.1\/57710\">thesis<\/a><br \/>\n(1975) or Gul Agha&#8217;s <a href=\"https:\/\/dspace.mit.edu\/handle\/1721.1\/6952\">thesis<\/a><br \/>\n(1985).<\/p>\n<p dir=\"auto\">Erlang first appeard later in 1986, but the Erlang developers were <a href=\"https:\/\/erlang.org\/pipermail\/erlang-questions\/2014-June\/079794.html\">not<br \/>\naware<\/a> of<br \/>\nthe actor model. In fact Robert Virding, one of the original Erlang designers,<br \/>\n<a href=\"https:\/\/erlang.org\/pipermail\/erlang-questions\/2014-June\/079865.html\">claims<\/a><br \/>\nthat it knowing about the actor model might even have slowed them down.<\/p>\n<p dir=\"auto\">Carl Hewitt has written a paper called <a href=\"https:\/\/arxiv.org\/abs\/1008.1459\"><em>Actor Model of Computation: Scalable<br \/>\nRobust Information Systems<\/em><\/a> (2015) which<br \/>\ndocuments the differences between Erlang&#8217;s processes and the actor model. <a href=\"http:\/\/github.com\/#user-content-fnref-1-b236052c3934bd6f7ea3426445bf45af\" data-footnote-backref aria-label=\"Back to content\"><g-emoji alias=\"leftwards_arrow_with_hook\" fallback-src=\"https:\/\/github.githubassets.com\/images\/icons\/emoji\/unicode\/21a9.png\">\u21a9<\/g-emoji><\/a><\/p>\n<\/li>\n<li id=\"user-content-fn-2-b236052c3934bd6f7ea3426445bf45af\">\n<p dir=\"auto\">Scala&#8217;s Akka seems to be of this opinion. They got something they call<br \/>\n&#8220;actors&#8221;, not to be confused with the actor model as per footnote 1, and<br \/>\nobligatory supervisors trees. They don&#8217;t appear to have any analogues of the<br \/>\nother Erlang behaviours though.<\/p>\n<p dir=\"auto\">Confusingly Akka has a concept called<br \/>\n<a href=\"https:\/\/doc.akka.io\/docs\/akka\/current\/general\/actors.html#behavior\">&#8220;behavior&#8221;<\/a>,<br \/>\nbut it has nothing to do with Erlang behaviours. <a href=\"http:\/\/github.com\/#user-content-fnref-2-b236052c3934bd6f7ea3426445bf45af\" data-footnote-backref aria-label=\"Back to content\"><g-emoji alias=\"leftwards_arrow_with_hook\" fallback-src=\"https:\/\/github.githubassets.com\/images\/icons\/emoji\/unicode\/21a9.png\">\u21a9<\/g-emoji><\/a><\/p>\n<\/li>\n<li id=\"user-content-fn-3-b236052c3934bd6f7ea3426445bf45af\">\n<p dir=\"auto\">The intuition being that since every program using the state monad can be<br \/>\nrewritten to a normal form where a single <code>read<\/code>\/<code>get<\/code> followed by a single<br \/>\n<code>write<\/code>\/<code>put<\/code>, it seems reasonable to assume that something similar would<br \/>\nwork for <code>recv<\/code> and <code>send<\/code> over the network. I forget the reference for the<br \/>\nstate monad normal form, either Plotkin and Power or Uustalu? <a href=\"http:\/\/github.com\/#user-content-fnref-3-b236052c3934bd6f7ea3426445bf45af\" data-footnote-backref aria-label=\"Back to content\"><g-emoji alias=\"leftwards_arrow_with_hook\" fallback-src=\"https:\/\/github.githubassets.com\/images\/icons\/emoji\/unicode\/21a9.png\">\u21a9<\/g-emoji><\/a><\/p>\n<\/li>\n<\/ol>\n<\/section><\/div>\n<p><a href=\"https:\/\/github.com\/stevana\/armstrong-distributed-systems\/blob\/main\/docs\/erlang-is-not-about.md\" class=\"button purchase\" rel=\"nofollow noopener\" target=\"_blank\">Read More<\/a><br \/>\n Augustine Latson<\/p>\n","protected":false},"excerpt":{"rendered":"<p>date 2023-01-18 Erlang&#8217;s not about lightweight processes and message passing&#8230; I used to think that the big idea of Erlang is its lightweight processes and message passing. Over the last couple of years I&#8217;ve realised that there&#8217;s a bigger insight to be had, and in this post I&#8217;d like to share it with you. Background<\/p>\n","protected":false},"author":1,"featured_media":602168,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[118530,29483,46],"tags":[],"class_list":["post-602167","post","type-post","status-publish","format-standard","has-post-thumbnail","category-erlangs","category-lightweight","category-technology"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/newsycanuse.com\/index.php\/wp-json\/wp\/v2\/posts\/602167","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/newsycanuse.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/newsycanuse.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/newsycanuse.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/newsycanuse.com\/index.php\/wp-json\/wp\/v2\/comments?post=602167"}],"version-history":[{"count":0,"href":"https:\/\/newsycanuse.com\/index.php\/wp-json\/wp\/v2\/posts\/602167\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/newsycanuse.com\/index.php\/wp-json\/wp\/v2\/media\/602168"}],"wp:attachment":[{"href":"https:\/\/newsycanuse.com\/index.php\/wp-json\/wp\/v2\/media?parent=602167"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/newsycanuse.com\/index.php\/wp-json\/wp\/v2\/categories?post=602167"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/newsycanuse.com\/index.php\/wp-json\/wp\/v2\/tags?post=602167"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}