Gray Soft / Language Comparisons / Erlang Message Passingtag:graysoftinc.com,2014-03-20:/posts/362014-04-05T14:26:32ZJames Edward Gray IIThe 15th Comment on "Erlang Message Passing"tag:graysoftinc.com,2008-09-29:/comments/2032014-04-05T14:26:32ZI don't think just Fiber is going to get us all the way to Erlang style parallelism. I feel it's are more a coroutine than an Erlang process.
However, matz was recently discussing [the plan for Ruby 2.0](http://lsrc2008.confreaks.com/09-yukihi...<p>I don't think just Fiber is going to get us all the way to Erlang style parallelism. I feel it's are more a coroutine than an Erlang process.</p>
<p>However, matz was recently discussing <a href="http://lsrc2008.confreaks.com/09-yukihiro-matz-matsumoto-ruby-past-present-and-future.html">the plan for Ruby 2.0</a> and it seems that Ruby is definitely going to head down this road in the future…</p>James Edward Gray IIThe 14th Comment on "Erlang Message Passing"tag:graysoftinc.com,2008-09-28:/comments/2022014-04-05T14:26:32ZHow much does Ruby 1.9 change things? Could we do this same thing with a single process and single thread and instead use a bazillion fibers?
What capabilities do you get get with an Erlang thread? Do you get something like Thread Local Storag...<p>How much does Ruby 1.9 change things? Could we do this same thing with a single process and single thread and instead use a bazillion fibers? </p>
<p>What capabilities do you get get with an Erlang thread? Do you get something like Thread Local Storage? If not then maybe a Ruby 1.9 fibers is a functional equivalent to an Erlang thead.</p>Mark RiverThe 13th Comment on "Erlang Message Passing"tag:graysoftinc.com,2007-09-15:/comments/1312014-04-05T14:23:32Z> I doubt the need for an Erlang bridge comes up often in a Rails application, but generally speaking such a thing could be useful anytime massive concurrency is called for.
I'm reading the same book in almost the same timeframe, and that lead ...<blockquote>
<p>I doubt the need for an Erlang bridge comes up often in a Rails application, but generally speaking such a thing could be useful anytime massive concurrency is called for.</p>
</blockquote>
<p>I'm reading the same book in almost the same timeframe, and that lead me to the same conclusions :)</p>Thibaut BarrèreThe 12th Comment on "Erlang Message Passing"tag:graysoftinc.com,2007-08-23:/comments/1222014-04-05T14:23:32ZI doubt the need for an Erlang bridge comes up often in a Rails application, but generally speaking such a thing could be useful anytime massive concurrency is called for.
I know Campfire has a C backend, but that might have been a place where ...<p>I doubt the need for an Erlang bridge comes up often in a Rails application, but generally speaking such a thing could be useful anytime massive concurrency is called for.</p>
<p>I know Campfire has a C backend, but that might have been a place where Erlang could have been used to good effect.</p>James Edward Gray IIThe 11th Comment on "Erlang Message Passing"tag:graysoftinc.com,2007-08-16:/comments/1212014-04-05T14:23:32ZWhen might Erlang-to-Ruby bridges be needed or wanted in a Ruby or Rails app?<p>When might Erlang-to-Ruby bridges be needed or wanted in a Ruby or Rails app?</p>Dan CroakThe 10th Comment on "Erlang Message Passing"tag:graysoftinc.com,2007-08-16:/comments/1202014-04-05T14:21:53Z> While I'm interested in Erlang, I don't think it's fair to compare languages based on OS threads. Instead, in your favourite language, emulate Erlang's processes. An event queue would suffice.
An event queue would not be fair either.
Erlan...<blockquote>
<p>While I'm interested in Erlang, I don't think it's fair to compare languages based on OS threads. Instead, in your favourite language, emulate Erlang's processes. An event queue would suffice.</p>
</blockquote>
<p>An event queue would not be fair either.</p>
<p>Erlang processes are more advanced than simple queues; they will automatically spread themselves out among the available processor cores on a machine. This means a cleverly written program will automatically run faster if you get another processor core in your compy. By using an event queue instead, it would still run on a single core.</p>HelgeThe 9th Comment on "Erlang Message Passing"tag:graysoftinc.com,2007-08-15:/comments/1192014-04-05T14:20:45Z```erlang
statistics(wall_clock).
% Do stuff
{_, Delta} = statistics(wall_clock).
```
Delta now holds the number of ms since you last called `statistics(wall_clock)`.
<div class="highlight highlight-erlang"><pre><span class="nb">statistics</span><span class="p">(</span><span class="n">wall_clock</span><span class="p">).</span>
<span class="c">% Do stuff</span>
<span class="p">{_,</span> <span class="nv">Delta</span><span class="p">}</span> <span class="o">=</span> <span class="nb">statistics</span><span class="p">(</span><span class="n">wall_clock</span><span class="p">).</span>
</pre></div>
<p>Delta now holds the number of ms since you last called <code>statistics(wall_clock)</code>.</p>Per MelinThe 8th Comment on "Erlang Message Passing"tag:graysoftinc.com,2007-08-15:/comments/1182014-03-27T01:38:24ZSo, a couple things you might be interested in:
The Omnibus Concurrency Library for Ruby, which provides Actor-style
concurrency: [http://rubyforge.org/projects/concurrent/](http://rubyforge.org/projects/concurrent/)
Erlectricity, a Ruby to...<p>So, a couple things you might be interested in:</p>
<p>The Omnibus Concurrency Library for Ruby, which provides Actor-style<br>
concurrency: <a href="http://rubyforge.org/projects/concurrent/">http://rubyforge.org/projects/concurrent/</a></p>
<p>Erlectricity, a Ruby to Erlang bridge: <a href="http://code.google.com/p/erlectricity/">http://code.google.com/p/erlectricity/</a></p>
<p>Rebar, another Ruby to Erlang bridge:<br><a href="http://rubyisawesome.com/2007/4/30/calling-erlang-from-ruby-teaser">http://rubyisawesome.com/2007/4/30/calling-erlang-from-ruby-teaser</a></p>Alex PayneThe 7th Comment on "Erlang Message Passing"tag:graysoftinc.com,2007-08-15:/comments/1172014-03-27T01:38:24ZThere are a couple of papers that talk about how the Actors model is
implemented in Scala:
[http://lamp.epfl.ch/~phaller/doc/haller07actorsunify.pdf](http://lamp.epfl.ch/~phaller/doc/haller07actorsunify.pdf) and
[http://lamp.epfl.ch/~phaller/do...<p>There are a couple of papers that talk about how the Actors model is<br>
implemented in Scala:<br><a href="http://lamp.epfl.ch/%7Ephaller/doc/haller07actorsunify.pdf">http://lamp.epfl.ch/~phaller/doc/haller07actorsunify.pdf</a> and<br><a href="http://lamp.epfl.ch/%7Ephaller/doc/haller06jmlc.pdf">http://lamp.epfl.ch/~phaller/doc/haller06jmlc.pdf</a>. See also<br><a href="http://lamp.epfl.ch/%7Ephaller/actors.html">http://lamp.epfl.ch/~phaller/actors.html</a> for other links. Would be<br>
interesting to compare on your machine.</p>Patrick WrightThe 6th Comment on "Erlang Message Passing"tag:graysoftinc.com,2007-08-15:/comments/1162014-04-05T14:20:45ZI did try to use the `statistics()` function at first, but I couldn't seem to figure out how to get correct answers out of it. I'm sure it was my fault though. Thanks for the timer link, that's very helpful.<p>I did try to use the <code>statistics()</code> function at first, but I couldn't seem to figure out how to get correct answers out of it. I'm sure it was my fault though. Thanks for the timer link, that's very helpful.</p>James Edward Gray IIThe 5th Comment on "Erlang Message Passing"tag:graysoftinc.com,2007-08-15:/comments/1152014-04-05T14:20:45ZInstead of your stopwatch, you can use timer:tc/3:
[http://www.erlang.org/doc/man/timer.html](http://www.erlang.org/doc/man/timer.html)
But if you do want to build your own timer it's usually easier to start with `erlang:statistics(runtime)` a...<p>Instead of your stopwatch, you can use timer:tc/3:<br><a href="http://www.erlang.org/doc/man/timer.html">http://www.erlang.org/doc/man/timer.html</a></p>
<p>But if you do want to build your own timer it's usually easier to start with <code>erlang:statistics(runtime)</code> and <code>erlang:statistics(wall_clock)</code>:<br><a href="http://www.erlang.org/doc/apps/kernel/index.html">http://www.erlang.org/doc/apps/kernel/index.html</a></p>Per MelinThe 4th Comment on "Erlang Message Passing"tag:graysoftinc.com,2007-08-15:/comments/1142014-04-05T14:27:05Z> While I'm interested in Erlang, I don't think it's fair to compare languages based on OS threads.
Ruby doesn't have native threads.
My really hacky version which models the Erlang way:
[http://snippets.dzone.com/posts/show/4421](http://sn...<blockquote>
<p>While I'm interested in Erlang, I don't think it's fair to compare languages based on OS threads.</p>
</blockquote>
<p>Ruby doesn't have native threads.</p>
<p>My really hacky version which models the Erlang way:<br><a href="http://snippets.dzone.com/posts/show/4421">http://snippets.dzone.com/posts/show/4421</a></p>
<p>It performs much better, but this functionality should be part of the ruby interpreter.</p>teki321The 3rd Comment on "Erlang Message Passing"tag:graysoftinc.com,2007-08-14:/comments/1132014-04-05T14:15:59ZI abstracted the Erlang code a little more because I'm less comfortable there and have to move in baby steps. Taking that into account, there wasn't a huge difference.<p>I abstracted the Erlang code a little more because I'm less comfortable there and have to move in baby steps. Taking that into account, there wasn't a huge difference.</p>James Edward Gray IIThe 2nd Comment on "Erlang Message Passing"tag:graysoftinc.com,2007-08-14:/comments/1122014-04-05T14:15:59ZRuby and Erlang are both awesome languages. Just out of curiosity, which one had fewer lines of code?<p>Ruby and Erlang are both awesome languages. Just out of curiosity, which one had fewer lines of code?</p>Jay WebThe 1st Comment on "Erlang Message Passing"tag:graysoftinc.com,2007-08-14:/comments/1112014-04-05T14:27:05ZWhile I'm interested in Erlang, I don't think it's fair to compare languages based on OS threads. Instead, in your favourite language, emulate Erlang's processes. An event queue would suffice.
I use a similar technique for simulating a computer...<p>While I'm interested in Erlang, I don't think it's fair to compare languages based on OS threads. Instead, in your favourite language, emulate Erlang's processes. An event queue would suffice.</p>
<p>I use a similar technique for simulating a computer network, and find it very fast (that said, I think Erlang's model would tend to simplify my networking code).</p>Ricky ClarksonErlang Message Passingtag:graysoftinc.com,2007-08-13:/posts/362014-04-05T14:27:05ZLet's take a look at something another programming language does well and see how we might bring at least some elements these features to Ruby.<p>Like many <a href="http://www.pragmaticprogrammer.com/">Pragmatic Programmer</a> fans, I've been having a look at <a href="http://www.erlang.org/">Erlang</a> recently by working my way through <a href="http://www.pragmaticprogrammer.com/titles/jaerlang/">Programming Erlang</a>. In the book, the author includes a challenge: build a message ring of <em>processes</em> of size M and send a message around the ring N times, timing how long this takes. The author also suggests doing this in other languages and comparing the results. Having now done this, I can tell you that it is an interesting exercise.</p>
<p>First, the Erlang results. Here's a sample run that creates 30,000 processes and sends a message around that ring 1,000 times:</p>
<pre><code>$ erl -noshell -s solution start 30000 1000
Creating 30000 processes (32768 allowed)...
Done.
Timer started.
Sending a message around the ring 1000 times...
Done: success
Time in seconds: 29
</code></pre>
<p>So we see about 30,000,000 message passes there in roughly 30 seconds. I should also note that Erlang creates those processes very, very fast. It's possible to raise the process limit shown there, but I'm more interested in comparing what these languages can do out of the box.</p>
<p>Now Ruby doesn't have an equivalent to Erlang processes, so we need to decide what the proper replacement is. The first thing I tried was <code>fork()</code>ing some Unix processes:</p>
<pre><code>$ ruby forked_mring.rb 100 10000
Creating 100 processes...
Timer started.
Sending a message around the ring 10000 times...
Done.
Done: success.
Time in seconds: 32
</code></pre>
<p>You should notice here the small number of processes I could create using the default limits imposed by my operating system. Again, it's possible to raise this limit but I don't think I'm going to get it up to 30,000 very easily. I did get these processes very quickly though, again.</p>
<p>So here we are passing 1,000,000 messages in about the same amount of time.</p>
<p>In an attempt to bypass the low process limit, I wrote another implementation with Ruby's threads. The results of that aren't too impressive though:</p>
<pre><code>$ ruby threaded_mring.rb 100 1000
Using the standard Ruby thread library.
Creating 100 processes...
Timer started.
Sending a message around the ring 1000 times...
Done: success.
Time in seconds: 32
$ ruby threaded_mring.rb 1000 4
Using the standard Ruby thread library.
Creating 1000 processes...
Timer started.
Sending a message around the ring 4 times...
Done: success.
Time in seconds: 30
</code></pre>
<p>You should see from the second run that it is possible to create quite a few more threads, but I need to mention that creating that many took around 15 seconds. Sadly, both of these runs paint an ugly picture: introducing synchronization just kills performance. Using the fastthread library doesn't help as much as we would like:</p>
<pre><code>$ ruby -rubygems threaded_mring.rb 100 1000
Using the fastthread library.
Creating 100 processes...
Timer started.
Sending a message around the ring 1000 times...
Done: success.
Time in seconds: 28
$ ruby -rubygems threaded_mring.rb 1000 5
Using the fastthread library.
Creating 1000 processes...
Timer started.
Sending a message around the ring 5 times...
Done: success.
Time in seconds: 29
</code></pre>
<p>So at best, we're passing 100,000 and 5,000 messages in our roughly 30 second timeframe, depending on how many processes we need.</p>
<p>Am I suggesting we all switch to Erlang? No. I've enjoyed seeing how the other side lives and I've learned a lot from getting into the functional mindset. Parts of Erlang are very impressive and concurrency is definitely one of them. It hasn't been enough to win me over from Ruby yet though. I couldn't ever see myself doing my day to day work without The Red Lady.</p>
<p>What I would love to see is some way to manage Erlang-like concurrency in Ruby. We could have some great fun building servers with that, I think.</p>
<p>I'll share the Erlang code here so the people that know the language better than me can provide corrections. First, here's the code the spawns processes and passes messages:</p>
<div class="highlight highlight-erlang"><pre><span class="p">-</span><span class="ni">module</span><span class="p">(</span><span class="n">mring</span><span class="p">).</span>
<span class="p">-</span><span class="ni">export</span><span class="p">([</span><span class="n">build</span><span class="o">/</span><span class="mi">1</span><span class="p">,</span> <span class="n">send_and_receive</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span> <span class="n">round_and_round</span><span class="o">/</span><span class="mi">3</span><span class="p">]).</span>
<span class="nf">build</span><span class="p">(</span><span class="nv">RingSize</span><span class="p">)</span> <span class="o">-></span>
<span class="nv">ParentPid</span> <span class="o">=</span> <span class="n">self</span><span class="p">(),</span>
<span class="nb">spawn</span><span class="p">(</span><span class="k">fun</span><span class="p">()</span> <span class="o">-></span> <span class="n">build</span><span class="p">(</span><span class="nv">RingSize</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="nv">ParentPid</span><span class="p">)</span> <span class="k">end</span><span class="p">).</span>
<span class="nf">build</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nv">StartPid</span><span class="p">)</span> <span class="o">-></span> <span class="n">forward</span><span class="p">(</span><span class="nv">StartPid</span><span class="p">);</span>
<span class="nf">build</span><span class="p">(</span><span class="nv">RingSize</span><span class="p">,</span> <span class="nv">StartPid</span><span class="p">)</span> <span class="o">-></span>
<span class="nv">ChildPid</span> <span class="o">=</span> <span class="nb">spawn</span><span class="p">(</span><span class="k">fun</span><span class="p">()</span> <span class="o">-></span> <span class="n">build</span><span class="p">(</span><span class="nv">RingSize</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="nv">StartPid</span><span class="p">)</span> <span class="k">end</span><span class="p">),</span>
<span class="n">forward</span><span class="p">(</span><span class="nv">ChildPid</span><span class="p">).</span>
<span class="nf">forward</span><span class="p">(</span><span class="nv">Pid</span><span class="p">)</span> <span class="o">-></span>
<span class="k">receive</span>
<span class="p">{</span><span class="n">message</span><span class="p">,</span> <span class="nv">Text</span><span class="p">,</span> <span class="nv">PassCount</span><span class="p">}</span> <span class="o">-></span>
<span class="nv">Pid</span> <span class="o">!</span> <span class="p">{</span><span class="n">message</span><span class="p">,</span> <span class="nv">Text</span><span class="p">,</span> <span class="nv">PassCount</span> <span class="o">+</span> <span class="mi">1</span><span class="p">},</span>
<span class="n">forward</span><span class="p">(</span><span class="nv">Pid</span><span class="p">)</span>
<span class="k">end</span><span class="p">.</span>
<span class="nf">send_and_receive</span><span class="p">(</span><span class="nv">Ring</span><span class="p">,</span> <span class="nv">Text</span><span class="p">)</span> <span class="o">-></span>
<span class="nv">Ring</span> <span class="o">!</span> <span class="p">{</span><span class="n">message</span><span class="p">,</span> <span class="nv">Text</span><span class="p">,</span> <span class="mi">0</span><span class="p">},</span>
<span class="k">receive</span> <span class="nv">Returned</span> <span class="o">-></span> <span class="nv">Returned</span> <span class="k">end</span><span class="p">.</span>
<span class="nf">round_and_round</span><span class="p">(_,</span> <span class="p">_,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">-></span> <span class="n">success</span><span class="p">;</span>
<span class="nf">round_and_round</span><span class="p">(</span><span class="nv">Ring</span><span class="p">,</span> <span class="nv">ProcessCount</span><span class="p">,</span> <span class="nv">Repeat</span><span class="p">)</span> <span class="o">-></span>
<span class="nv">Check</span> <span class="o">=</span> <span class="s">"Checking the ring..."</span><span class="p">,</span>
<span class="k">case</span> <span class="n">send_and_receive</span><span class="p">(</span><span class="nv">Ring</span><span class="p">,</span> <span class="s">"Checking the ring..."</span><span class="p">)</span> <span class="k">of</span>
<span class="p">{</span><span class="n">message</span><span class="p">,</span> <span class="nv">Check</span><span class="p">,</span> <span class="nv">ProcessCount</span><span class="p">}</span> <span class="o">-></span>
<span class="n">round_and_round</span><span class="p">(</span><span class="nv">Ring</span><span class="p">,</span> <span class="nv">ProcessCount</span><span class="p">,</span> <span class="nv">Repeat</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
<span class="nv">Unexpected</span> <span class="o">-></span> <span class="p">{</span><span class="n">failure</span><span class="p">,</span> <span class="nv">Unexpected</span><span class="p">}</span>
<span class="k">end</span><span class="p">.</span>
</pre></div>
<p>Next, we have a little helper I wrote to time things. I'm pretty confident there must be a better way to do this, but all my attempts to find it failed. Help me Erlang Jedi:</p>
<div class="highlight highlight-erlang"><pre><span class="p">-</span><span class="ni">module</span><span class="p">(</span><span class="n">stopwatch</span><span class="p">).</span>
<span class="p">-</span><span class="ni">export</span><span class="p">([</span><span class="n">time_this</span><span class="o">/</span><span class="mi">1</span><span class="p">,</span> <span class="n">time_and_print</span><span class="o">/</span><span class="mi">1</span><span class="p">]).</span>
<span class="nf">time_this</span><span class="p">(</span><span class="nv">Fun</span><span class="p">)</span> <span class="o">-></span>
<span class="p">{</span><span class="nv">StartMega</span><span class="p">,</span> <span class="nv">StartSec</span><span class="p">,</span> <span class="nv">StartMicro</span><span class="p">}</span> <span class="o">=</span> <span class="n">now</span><span class="p">(),</span>
<span class="nv">Fun</span><span class="p">(),</span>
<span class="p">{</span><span class="nv">EndMega</span><span class="p">,</span> <span class="nv">EndSec</span><span class="p">,</span> <span class="nv">EndMicro</span><span class="p">}</span> <span class="o">=</span> <span class="n">now</span><span class="p">(),</span>
<span class="p">(</span><span class="nv">EndMega</span> <span class="o">*</span> <span class="mi">1000000</span> <span class="o">+</span> <span class="nv">EndSec</span> <span class="o">+</span> <span class="nv">EndMicro</span> <span class="ow">div</span> <span class="mi">1000000</span><span class="p">)</span> <span class="o">-</span>
<span class="p">(</span><span class="nv">StartMega</span> <span class="o">*</span> <span class="mi">1000000</span> <span class="o">+</span> <span class="nv">StartSec</span> <span class="o">+</span> <span class="nv">StartMicro</span> <span class="ow">div</span> <span class="mi">1000000</span><span class="p">).</span>
<span class="nf">time_and_print</span><span class="p">(</span><span class="nv">Fun</span><span class="p">)</span> <span class="o">-></span>
<span class="nn">io</span><span class="p">:</span><span class="nf">format</span><span class="p">(</span><span class="s">"Timer started.</span><span class="si">~n</span><span class="s">"</span><span class="p">),</span>
<span class="nv">Time</span> <span class="o">=</span> <span class="n">time_this</span><span class="p">(</span><span class="nv">Fun</span><span class="p">),</span>
<span class="nn">io</span><span class="p">:</span><span class="nf">format</span><span class="p">(</span><span class="s">"Time in seconds: </span><span class="si">~p~n</span><span class="s">"</span><span class="p">,</span> <span class="p">[</span><span class="nv">Time</span><span class="p">]).</span>
</pre></div>
<p>Finally we have the application code that glues these modules together:</p>
<div class="highlight highlight-erlang"><pre><span class="p">-</span><span class="ni">module</span><span class="p">(</span><span class="n">solution</span><span class="p">).</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="nf">start</span><span class="p">([</span><span class="nv">ProcessesArg</span><span class="p">,</span> <span class="nv">CyclesArg</span><span class="p">])</span> <span class="o">-></span>
<span class="nv">Processes</span> <span class="o">=</span> <span class="nb">list_to_integer</span><span class="p">(</span><span class="nb">atom_to_list</span><span class="p">(</span><span class="nv">ProcessesArg</span><span class="p">)),</span>
<span class="nv">Cycles</span> <span class="o">=</span> <span class="nb">list_to_integer</span><span class="p">(</span><span class="nb">atom_to_list</span><span class="p">(</span><span class="nv">CyclesArg</span><span class="p">)),</span>
<span class="nn">io</span><span class="p">:</span><span class="nf">format</span><span class="p">(</span> <span class="s">"Creating </span><span class="si">~p</span><span class="s"> processes (</span><span class="si">~p</span><span class="s"> allowed)...</span><span class="si">~n</span><span class="s">"</span><span class="p">,</span>
<span class="p">[</span><span class="nv">Processes</span><span class="p">,</span> <span class="nn">erlang</span><span class="p">:</span><span class="nb">system_info</span><span class="p">(</span><span class="n">process_limit</span><span class="p">)]),</span>
<span class="nv">Ring</span> <span class="o">=</span> <span class="nn">mring</span><span class="p">:</span><span class="nf">build</span><span class="p">(</span><span class="nv">Processes</span><span class="p">),</span>
<span class="nn">io</span><span class="p">:</span><span class="nf">format</span><span class="p">(</span><span class="s">"Done.</span><span class="si">~n</span><span class="s">"</span><span class="p">),</span>
<span class="nn">stopwatch</span><span class="p">:</span><span class="nf">time_and_print</span><span class="p">(</span>
<span class="k">fun</span><span class="p">()</span> <span class="o">-></span>
<span class="nn">io</span><span class="p">:</span><span class="nf">format</span><span class="p">(</span><span class="s">"Sending a message around the ring </span><span class="si">~p</span><span class="s"> times...</span><span class="si">~n</span><span class="s">"</span><span class="p">,</span> <span class="p">[</span><span class="nv">Cycles</span><span class="p">]),</span>
<span class="nv">Result</span> <span class="o">=</span> <span class="nn">mring</span><span class="p">:</span><span class="nf">round_and_round</span><span class="p">(</span><span class="nv">Ring</span><span class="p">,</span> <span class="nv">Processes</span><span class="p">,</span> <span class="nv">Cycles</span><span class="p">),</span>
<span class="nn">io</span><span class="p">:</span><span class="nf">format</span><span class="p">(</span><span class="s">"Done: </span><span class="si">~p~n</span><span class="s">"</span><span class="p">,</span> <span class="p">[</span><span class="nv">Result</span><span class="p">])</span>
<span class="k">end</span>
<span class="p">),</span>
<span class="nn">init</span><span class="p">:</span><span class="nf">stop</span><span class="p">().</span>
</pre></div>
<p>You will see the Ruby solutions in <a href="http://www.rubyquiz.com/quiz135.html">this week's Ruby Quiz</a>.</p>James Edward Gray II