Jekyll2022-02-09T13:59:01+00:00http://troikatech.com/feed.xmlTroika TechRuby and JS in the streets, Haskell and friends between the sheets.Concurrent I/O using dry-monads’ Task2022-02-08T10:53:00+00:002022-02-08T10:53:00+00:00http://troikatech.com/blog/2022/02/08/concurrent-io-using-dry-monads-tasks<p><a href="https://dry-rb.org/gems/dry-monads">dry-monads</a> is a <em>beautiful</em> gem. It brings a few valuable Monads to Ruby and strives to make them fit snuggly among the other constructs we usually employ when building our software. One such Monad is <a href="https://dry-rb.org/gems/dry-monads/1.3/task/">Task</a>.</p>
<p><code class="language-plaintext highlighter-rouge">Task</code> is a lot like <a href="https://pursuit.purescript.org/packages/purescript-aff/6.0.0">PureScript’s <code class="language-plaintext highlighter-rouge">Aff</code></a>, or <a href="https://gcanti.github.io/fp-ts/modules/Task.ts.html">fp-ts’s <code class="language-plaintext highlighter-rouge">Task</code></a>: it represents an asynchronous computation that creates side-effects, sometimes resulting in failures. By being a Monad, we can rely on the same techniques and infrastructure available to siblings like <code class="language-plaintext highlighter-rouge">Maybe</code> and <code class="language-plaintext highlighter-rouge">Result</code>.</p>
<p>Its implementation is, ultimately, dependent on <code class="language-plaintext highlighter-rouge">Thread</code>. Suppose you’re familiar with concurrency and parallelism in Ruby. In that case, you’re probably aware that <code class="language-plaintext highlighter-rouge">Thread</code> doesn’t give you parallelism in CRuby (JRuby is another story) due to the <em>global VM lock</em> (also called <em>global interpreter lock</em>, or GIL, a relic of Ruby pre-1.9). Concurrency is a different matter.</p>
<p>Threaded code can be run concurrently in the CRuby VM when a <code class="language-plaintext highlighter-rouge">Thread</code> is waiting on I/O. If you’ve ever heard Ruby’s performance is not relevant in a world of network calls and file operations, understanding that particularity can be very relevant to building faster programs. That is why Sidekiq, Puma, and many other projects are very successful (and often fast), even without parallelism.</p>
<p><code class="language-plaintext highlighter-rouge">Task</code> offers you a principled way to build complex call chains that might fail without sacrificing readability or introducing complex error handling code. If you’ve ever worked with Promises in JavaScript, it should be very familiar.</p>
<h2 id="the-basics">The basics</h2>
<p>You can promote (or, using the FP jargon, <em>lift</em>) any computation to a <code class="language-plaintext highlighter-rouge">Task</code> by using its constructor:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span> <span class="n">irb</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">001</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="nb">require</span> <span class="s2">"dry/monads"</span>
<span class="o">=></span> <span class="kp">true</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">002</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="kp">include</span> <span class="no">Dry</span><span class="o">::</span><span class="no">Monads</span><span class="p">[</span><span class="ss">:task</span><span class="p">]</span>
<span class="o">=></span> <span class="no">Object</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">003</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="no">Task</span> <span class="p">{</span> <span class="s2">"success"</span> <span class="p">}</span>
<span class="o">=></span> <span class="no">Task</span><span class="p">(</span><span class="sc">?)</span>
</code></pre></div></div>
<p>Since it’s an asynchronous computation, it doesn’t block or immediately have a value (unless you run it in the <code class="language-plaintext highlighter-rouge">:immediate</code> thread pool — see the documentation). That’s why you see <code class="language-plaintext highlighter-rouge">Task(?)</code>. The computation <em>does</em> start immediately; if your <code class="language-plaintext highlighter-rouge">Task</code> consists of an HTTP call, it’s in-flight as soon as a thread is available for scheduling. This is different from other languages and libraries, which often separate describing a computation from running it.</p>
<p>When you ask for a Task’s value (with <code class="language-plaintext highlighter-rouge">Task#value!</code>), it blocks until it can produce one:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">004</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="k">def</span> <span class="nf">measure</span><span class="p">;</span> <span class="n">t0</span> <span class="o">=</span> <span class="no">Time</span><span class="p">.</span><span class="nf">now</span><span class="p">;</span> <span class="k">yield</span><span class="p">;</span> <span class="n">t1</span> <span class="o">=</span> <span class="no">Time</span><span class="p">.</span><span class="nf">now</span><span class="p">;</span> <span class="n">t1</span> <span class="o">-</span> <span class="n">t0</span><span class="p">;</span> <span class="k">end</span>
<span class="ss">:measure</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">005</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="n">measure</span> <span class="p">{</span> <span class="no">Task</span> <span class="p">{</span> <span class="nb">sleep</span> <span class="mi">10</span><span class="p">;</span> <span class="s2">"success"</span> <span class="p">}.</span><span class="nf">value!</span> <span class="p">}</span>
<span class="o">=></span> <span class="mf">10.000725254</span>
</code></pre></div></div>
<p>Like other Functors, it’s possible to alter (with <code class="language-plaintext highlighter-rouge">Task#fmap</code>) its value:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">006</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="no">Task</span> <span class="p">{</span> <span class="s2">"success"</span> <span class="p">}.</span><span class="nf">fmap</span> <span class="p">{</span> <span class="s2">"</span><span class="si">#{</span><span class="n">_1</span><span class="si">}</span><span class="s2">: it might be fleeting"</span> <span class="p">}.</span><span class="nf">value!</span>
<span class="o">=></span> <span class="s2">"success: it might be fleeting"</span>
</code></pre></div></div>
<p>Like other Monads, it’s possible to chain (with <code class="language-plaintext highlighter-rouge">Task#bind</code>) computations:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">007</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="n">success</span> <span class="o">=</span> <span class="no">Task</span> <span class="p">{</span> <span class="s2">"success"</span> <span class="p">}</span>
<span class="o">=></span> <span class="no">Task</span><span class="p">(</span><span class="sc">?)</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">00</span><span class="mi">8</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="n">success</span><span class="p">.</span><span class="nf">bind</span> <span class="p">{</span> <span class="o">|</span><span class="n">a</span><span class="o">|</span> <span class="no">Task</span> <span class="p">{</span> <span class="s2">"fame"</span> <span class="p">}.</span><span class="nf">fmap</span> <span class="p">{</span> <span class="o">|</span><span class="n">b</span><span class="o">|</span> <span class="s2">"</span><span class="si">#{</span><span class="n">a</span><span class="si">}</span><span class="s2"> and </span><span class="si">#{</span><span class="n">b</span><span class="si">}</span><span class="s2">"</span> <span class="p">}</span> <span class="p">}.</span><span class="nf">value!</span>
<span class="s2">"success and fame"</span>
</code></pre></div></div>
<p>As well as use <em>do notation</em>:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">00</span><span class="mi">9</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="kp">include</span> <span class="no">Dry</span><span class="o">::</span><span class="no">Monads</span><span class="p">[</span><span class="ss">:do</span><span class="p">]</span>
<span class="o">=></span> <span class="no">Object</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">010</span><span class="p">:</span><span class="mi">1</span><span class="o">*</span> <span class="k">def</span> <span class="nf">doing_well</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">011</span><span class="p">:</span><span class="mi">1</span><span class="o">*</span> <span class="n">success</span> <span class="o">=</span> <span class="k">yield</span> <span class="no">Task</span> <span class="p">{</span> <span class="s2">"success"</span> <span class="p">}</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">012</span><span class="p">:</span><span class="mi">1</span><span class="o">*</span> <span class="n">fame</span> <span class="o">=</span> <span class="k">yield</span> <span class="no">Task</span> <span class="p">{</span> <span class="s2">"fame"</span> <span class="p">}</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">013</span><span class="p">:</span><span class="mi">1</span><span class="o">*</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">014</span><span class="p">:</span><span class="mi">1</span><span class="o">*</span> <span class="no">Task</span> <span class="p">{</span> <span class="s2">"</span><span class="si">#{</span><span class="n">success</span><span class="si">}</span><span class="s2"> and </span><span class="si">#{</span><span class="n">fame</span><span class="si">}</span><span class="s2">"</span> <span class="p">}</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">015</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="k">end</span>
<span class="o">=></span> <span class="ss">:doing_well</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">016</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="n">doing_well</span><span class="p">.</span><span class="nf">value!</span>
<span class="o">=></span> <span class="s2">"success and fame"</span>
</code></pre></div></div>
<p>As previously mentioned, <code class="language-plaintext highlighter-rouge">Task</code> models the possibility of your computation failing. That means that if the block raises an error, the <code class="language-plaintext highlighter-rouge">Task</code> will wrap it and behave accordingly downstream. So, when you call <code class="language-plaintext highlighter-rouge">value!</code>, it will raise the error; when you call <code class="language-plaintext highlighter-rouge">map</code> or <code class="language-plaintext highlighter-rouge">bind</code>, nothing will happen:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">017</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="no">Task</span> <span class="p">{</span> <span class="nb">fail</span> <span class="s2">"Oh no!"</span> <span class="p">}.</span><span class="nf">value!</span>
<span class="c1"># ...</span>
<span class="no">RuntimeError</span> <span class="p">(</span><span class="no">Oh</span> <span class="n">no!</span><span class="p">)</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">017</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="no">Task</span> <span class="p">{</span> <span class="nb">fail</span> <span class="s2">"Stop!"</span> <span class="p">}.</span><span class="nf">fmap</span> <span class="p">{</span> <span class="mi">10</span> <span class="p">}.</span><span class="nf">value!</span>
<span class="c1"># ...</span>
<span class="no">RuntimeError</span> <span class="p">(</span><span class="no">Stop</span><span class="o">!</span><span class="p">)</span>
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">Task</code> also defines a few other combinators, which can be very useful when building more intricate computations.</p>
<h2 id="when-the-thing-you-need-is-not-a-monad">When the thing you need is not a Monad</h2>
<p>Imagine making three HTTP requests to gather all the data you need to build a report. On average, the first takes 320ms, the second takes 2000ms, and the third takes 1500ms. If you made the calls sequentially, you would need (again, on average) at least 3820ms to have all the data before you could start any processing; doing them concurrently will take at most 2000ms (i.e., the duration of the slowest request).</p>
<p>Monads are, however, inherently sequential. That’s why they’re commonly called <a href="http://book.realworldhaskell.org/read/monads.html">“programmable semicolons”</a>: the fate of the second operation is bound to what happens in the first. This characteristic is at odds with what we want to achieve. <code class="language-plaintext highlighter-rouge">Task</code> being a Monad is not what will solve our problem.</p>
<p>Every <em>Monad</em> is also an <em>Applicative Functor</em> (and a <em>Functor</em>). <a href="http://www.staff.city.ac.uk/~ross/papers/Applicative.pdf">Applicative Functors</a>, in very simplified terms (<em>don’t @ me</em>), allow us to run an <em>effectful</em> computation (basically, a <em>structure-building operation</em>, like, say, constructing a <code class="language-plaintext highlighter-rouge">Maybe</code>) by lifting a function into a structure and applying it to values in that same structure. Being an Applicative Functor does not imply a dependency between computations (though, of course, applying a function resolves them in a certain order), and this means code that relies on it also does not require operations to run one after the other.</p>
<p><code class="language-plaintext highlighter-rouge">dry-monads</code> implements that notion for its structures. We wrap the function by calling <code class="language-plaintext highlighter-rouge">pure</code> on the structure and provide it with arguments using <code class="language-plaintext highlighter-rouge">apply</code>:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">01</span><span class="mi">8</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="no">Task</span><span class="p">.</span><span class="nf">pure</span> <span class="p">{</span> <span class="o">|</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="o">|</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span> <span class="p">}.</span><span class="nf">apply</span><span class="p">(</span><span class="no">Task</span> <span class="p">{</span> <span class="mi">10</span> <span class="p">}).</span><span class="nf">apply</span><span class="p">(</span><span class="no">Task</span> <span class="p">{</span> <span class="mi">20</span> <span class="p">}).</span><span class="nf">value!</span>
<span class="mi">30</span>
</code></pre></div></div>
<p>Being an Applicative gives us many tools to build code that isn’t overly restricted just because we want it to short-circuit in some situations. The one that’s most relevant to our use case is <code class="language-plaintext highlighter-rouge">traverse</code>.</p>
<h2 id="traverse">traverse</h2>
<p>People often joke that the answer is <code class="language-plaintext highlighter-rouge">traverse</code>, no matter the question. In Haskell, it relies on a structure being <code class="language-plaintext highlighter-rouge">Traversable</code>, which means you can go element by element and perform an action on each, collecting the results as it goes. By that description, you might be thinking it’s a lot like <code class="language-plaintext highlighter-rouge">fmap</code>. And you’re right! The main difference is that instead of building individual effects (e.g., <code class="language-plaintext highlighter-rouge">fmap</code>ping each element of an Array into a <code class="language-plaintext highlighter-rouge">Maybe</code>), it considers them in the aggregate.</p>
<p>I know that’s very vague. So let’s look at it like this: if you have an <code class="language-plaintext highlighter-rouge">Array</code> and you want to <code class="language-plaintext highlighter-rouge">traverse</code> it by producing a <code class="language-plaintext highlighter-rouge">Maybe</code> for each element, you will end up with a <code class="language-plaintext highlighter-rouge">Maybe</code> with an <code class="language-plaintext highlighter-rouge">Array</code> inside it. If any of the <code class="language-plaintext highlighter-rouge">Maybe</code>s you create is a <code class="language-plaintext highlighter-rouge">None</code>, you’ll have a <code class="language-plaintext highlighter-rouge">None</code>; otherwise, you’ll have a <code class="language-plaintext highlighter-rouge">Some([...])</code> (like <code class="language-plaintext highlighter-rouge">Promise.all</code>, if you know JavaScript, only more general).</p>
<p><code class="language-plaintext highlighter-rouge">dry-monads</code> defines only two <code class="language-plaintext highlighter-rouge">Traversable</code> structures; we’ll use one called <a href="https://dry-rb.org/gems/dry-monads/1.3/list/"><code class="language-plaintext highlighter-rouge">List</code></a>. If you ever wondered why that exists, it’s time to let it shine:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">01</span><span class="mi">9</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="kp">include</span> <span class="no">Dry</span><span class="o">::</span><span class="no">Monads</span><span class="p">[</span><span class="ss">:list</span><span class="p">]</span>
<span class="o">=></span> <span class="no">Object</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">020</span><span class="p">:</span><span class="mi">0</span><span class="o">*></span> <span class="no">List</span><span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span> <span class="p">\</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">021</span><span class="p">:</span><span class="mi">0</span><span class="o">*></span> <span class="p">.</span><span class="nf">typed</span><span class="p">(</span><span class="no">Task</span><span class="p">)</span> <span class="p">\</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">022</span><span class="p">:</span><span class="mi">0</span><span class="o">*></span> <span class="p">.</span><span class="nf">traverse</span> <span class="p">{</span> <span class="o">|</span><span class="n">n</span><span class="o">|</span> <span class="no">Task</span> <span class="p">{</span> <span class="nb">sleep</span> <span class="n">n</span><span class="p">;</span> <span class="nb">puts</span> <span class="s2">"Finished sleeping </span><span class="si">#{</span><span class="n">n</span><span class="si">}</span><span class="s2">"</span><span class="p">;</span> <span class="n">n</span> <span class="o">*</span> <span class="mi">100</span> <span class="p">}</span> <span class="p">}</span> <span class="p">\</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">023</span><span class="p">:</span><span class="mi">0</span><span class="o">*></span> <span class="p">.</span><span class="nf">value!</span>
<span class="no">Finished</span> <span class="n">sleeping</span> <span class="mi">1</span>
<span class="no">Finished</span> <span class="n">sleeping</span> <span class="mi">2</span>
<span class="no">Finished</span> <span class="n">sleeping</span> <span class="mi">3</span>
<span class="o">=></span> <span class="no">List</span><span class="p">[</span><span class="mi">300</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">100</span><span class="p">]</span>
</code></pre></div></div>
<p>Let’s parse this. With <code class="language-plaintext highlighter-rouge">List[1, 2, 3]</code>, we build a <code class="language-plaintext highlighter-rouge">Dry::Monads::List</code>. Then comes an odd detail: <code class="language-plaintext highlighter-rouge">typed(Task)</code>. Unlike Haskell or PureScript, which know what <code class="language-plaintext highlighter-rouge">Applicative</code> we’ll be using for our effect at compile-time, <code class="language-plaintext highlighter-rouge">dry-monads</code> needs us to specify how to perform the switcheroo (i.e., which structure to call <code class="language-plaintext highlighter-rouge">pure</code> on when beginning the aggregation). Then we specify the <em>structure-building operation</em> by providing a block to <code class="language-plaintext highlighter-rouge">traverse</code>, which will construct a <code class="language-plaintext highlighter-rouge">Task</code> for each number.</p>
<p>At this point, we have a <code class="language-plaintext highlighter-rouge">Task[List[Integer]]</code>. Calling <code class="language-plaintext highlighter-rouge">value!</code> will block until that <code class="language-plaintext highlighter-rouge">Task</code> is done and return the <code class="language-plaintext highlighter-rouge">List[Integer]</code>.</p>
<h2 id="putting-it-together">Putting it together</h2>
<p>Let’s go back to the HTTP call scenario we described earlier. When using <code class="language-plaintext highlighter-rouge">Task</code> as our effect, relying on <code class="language-plaintext highlighter-rouge">traverse</code> means the calls will be run <em>concurrently</em>, like we wanted, being only as slow as the slowest call. We can see that in practice:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span> <span class="n">irb</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">001</span><span class="p">:</span><span class="mi">0</span><span class="o">*></span> <span class="nb">require</span> <span class="s2">"net/http"</span>
<span class="kp">true</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">002</span><span class="p">:</span><span class="mi">0</span><span class="o">*></span> <span class="nb">require</span> <span class="s2">"dry/monads"</span>
<span class="kp">true</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">003</span><span class="p">:</span><span class="mi">0</span><span class="o">*></span> <span class="k">def</span> <span class="nf">measure</span><span class="p">;</span> <span class="n">t0</span> <span class="o">=</span> <span class="no">Time</span><span class="p">.</span><span class="nf">now</span><span class="p">;</span> <span class="k">yield</span><span class="p">;</span> <span class="n">t1</span> <span class="o">=</span> <span class="no">Time</span><span class="p">.</span><span class="nf">now</span><span class="p">;</span> <span class="n">t1</span> <span class="o">-</span> <span class="n">t0</span><span class="p">;</span> <span class="k">end</span>
<span class="ss">:measure</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">004</span><span class="p">:</span><span class="mi">1</span><span class="o">*></span> <span class="k">def</span> <span class="nf">fetch_example</span><span class="p">;</span> <span class="no">Net</span><span class="o">::</span><span class="no">HTTP</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="s2">"example.com"</span><span class="p">,</span> <span class="s2">"/index.html"</span><span class="p">);</span> <span class="k">end</span>
<span class="ss">:fetch_example</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">005</span><span class="p">:</span><span class="mi">1</span><span class="o">*></span> <span class="kp">include</span> <span class="no">Dry</span><span class="o">::</span><span class="no">Monads</span><span class="p">[</span><span class="ss">:task</span><span class="p">,</span> <span class="ss">:list</span><span class="p">]</span>
<span class="o">=></span> <span class="no">Object</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">006</span><span class="p">:</span><span class="mi">1</span><span class="o">*></span> <span class="k">def</span> <span class="nf">sequential</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">007</span><span class="p">:</span><span class="mi">1</span><span class="o">*></span> <span class="p">(</span><span class="mi">0</span><span class="o">..</span><span class="mi">9</span><span class="p">).</span><span class="nf">reduce</span><span class="p">(</span><span class="no">Task</span><span class="p">.</span><span class="nf">pure</span><span class="p">([]))</span> <span class="k">do</span> <span class="o">|</span><span class="n">acc</span><span class="p">,</span> <span class="n">_</span><span class="o">|</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">00</span><span class="mi">8</span><span class="p">:</span><span class="mi">1</span><span class="o">*></span> <span class="n">acc</span><span class="p">.</span><span class="nf">bind</span> <span class="p">{</span> <span class="o">|</span><span class="n">vs</span><span class="o">|</span> <span class="no">Task</span> <span class="p">{</span> <span class="n">fetch_example</span> <span class="p">}.</span><span class="nf">fmap</span> <span class="p">{</span> <span class="o">|</span><span class="n">v</span><span class="o">|</span> <span class="n">vs</span> <span class="o">+</span> <span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="p">}</span> <span class="p">}</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">00</span><span class="mi">9</span><span class="p">:</span><span class="mi">1</span><span class="o">*></span> <span class="k">end</span><span class="p">.</span><span class="nf">value!</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">010</span><span class="p">:</span><span class="mi">1</span><span class="o">*></span> <span class="k">end</span>
<span class="ss">:sequential</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">011</span><span class="p">:</span><span class="mi">1</span><span class="o">*></span> <span class="k">def</span> <span class="nf">concurrent</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">012</span><span class="p">:</span><span class="mi">1</span><span class="o">*></span> <span class="no">List</span><span class="p">[</span><span class="o">*</span><span class="p">(</span><span class="mi">0</span><span class="o">..</span><span class="mi">9</span><span class="p">)]</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">013</span><span class="p">:</span><span class="mi">1</span><span class="o">*></span> <span class="p">.</span><span class="nf">typed</span><span class="p">(</span><span class="no">Task</span><span class="p">)</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">014</span><span class="p">:</span><span class="mi">1</span><span class="o">*></span> <span class="p">.</span><span class="nf">traverse</span> <span class="p">{</span> <span class="no">Task</span> <span class="p">{</span> <span class="n">fetch_example</span> <span class="p">}</span> <span class="p">}</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">015</span><span class="p">:</span><span class="mi">1</span><span class="o">*></span> <span class="p">.</span><span class="nf">value!</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">016</span><span class="p">:</span><span class="mi">1</span><span class="o">*></span> <span class="k">end</span>
<span class="ss">:concurrent</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">017</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="n">measure</span> <span class="p">{</span> <span class="n">sequential</span> <span class="p">}</span>
<span class="o">=></span> <span class="mf">3.134079812</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">01</span><span class="mi">8</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="n">measure</span> <span class="p">{</span> <span class="n">concurrent</span> <span class="p">}</span>
<span class="o">=></span> <span class="mf">0.300010159</span>
</code></pre></div></div>
<p>One order of magnitude faster while keeping every guarantee <code class="language-plaintext highlighter-rouge">dry-monads</code> provides in your toolbelt. That’s pretty great!</p>
<h2 id="wrapping-up">Wrapping up</h2>
<p>This technique can easily provide your software with a speed boost. In addition, the fact that it creates a grammar for how you structure problems that is very consistent and robust is a great benefit that can be a positive change for any codebase.</p>
<p>There are, of course, potential problems. Thread starvation. Team buy-in. Having to onboard new developers. No static analysis support (<a href="https://github.com/bellroy/dry-monads-sorbet">unless you’re using Sorbet</a>; even so, barely) to let you know you’re using <code class="language-plaintext highlighter-rouge">fmap</code> and you should be using <code class="language-plaintext highlighter-rouge">bind</code> or vice-versa. Still, I believe the <em>pros</em> easily beat the <em>cons</em>. Hopefully, after reading this article, you do too.</p>dry-monads is a beautiful gem. It brings a few valuable Monads to Ruby and strives to make them fit snuggly among the other constructs we usually employ when building our software. One such Monad is Task.Confident Ruby in the presence of nil2022-02-02T12:34:00+00:002022-02-02T12:34:00+00:00http://troikatech.com/blog/2022/02/02/confident-ruby-in-the-presence-of-nil<p>When people talk about working with Ruby, the usual <em>spiel</em> is about joy, humans at the center, <a href="https://www.wordsense.eu/MINASWAN/">MINASWAN</a>, kittens, and all that sparkles. However, they rarely address the role of anxiety in our day to day. Or rather, of one specific concern: will I get a <code class="language-plaintext highlighter-rouge">NoMethodError</code> due to an unexpected <code class="language-plaintext highlighter-rouge">nil</code>?</p>
<p>Think about it. If you ask an Array for a value that’s not there, you get <code class="language-plaintext highlighter-rouge">nil</code>. If you call a method that produces a side-effect, you often get <code class="language-plaintext highlighter-rouge">nil</code>. If you call another method and it stops when a precondition fails, it might return <code class="language-plaintext highlighter-rouge">nil</code>. Even writing this list made me sweat a little.</p>
<p>That inescapable reality often leads to patterns like:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">do_something</span> <span class="k">if</span> <span class="n">something</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">y</span> <span class="k">if</span> <span class="n">z</span>
<span class="n">foo</span> <span class="o">=</span> <span class="n">bar</span> <span class="p">?</span> <span class="n">bar</span><span class="p">.</span><span class="nf">size</span> <span class="p">:</span> <span class="o">-</span><span class="mi">1</span>
</code></pre></div></div>
<p>We get used to it, but it’s hardly the most fluent or confident way to write code. Consider the following:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">rejigger_oldest_widget</span><span class="p">(</span><span class="n">widgets</span><span class="p">,</span> <span class="n">max_age_years</span><span class="p">)</span>
<span class="n">oldest_widget</span> <span class="o">=</span> <span class="n">widgets</span>
<span class="p">.</span><span class="nf">select</span><span class="p">(</span><span class="o">&</span><span class="ss">:working?</span><span class="p">)</span>
<span class="p">.</span><span class="nf">find</span> <span class="p">{</span> <span class="n">_1</span><span class="p">.</span><span class="nf">age_in_years</span> <span class="o"><=</span> <span class="n">max_age_years</span> <span class="p">}</span>
<span class="k">if</span> <span class="n">oldest_widget</span>
<span class="n">oldest_widget</span>
<span class="p">.</span><span class="nf">rejigger</span>
<span class="p">.</span><span class="nf">shuffle</span>
<span class="p">.</span><span class="nf">shine</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>It’s not awful, but it’s hardly remarkable. What if <code class="language-plaintext highlighter-rouge">rejigger</code>, <code class="language-plaintext highlighter-rouge">shuffle</code>, or <code class="language-plaintext highlighter-rouge">shine</code> also return <code class="language-plaintext highlighter-rouge">nil</code> on occasion? Or worse, what if they <em>all</em> might produce one? Do we despair?</p>
<h2 id="our-knight-in-shiny-armor">Our knight in shiny armor</h2>
<p>Like many other languages, the solution Ruby (since 2.3) has found for this problem is the safe navigation operator, represented by <code class="language-plaintext highlighter-rouge">&.</code>. It’s neither only <code class="language-plaintext highlighter-rouge">&</code> nor simply <code class="language-plaintext highlighter-rouge">.</code>, but <code class="language-plaintext highlighter-rouge">&.</code>, a worthy unit that allows us to change <code class="language-plaintext highlighter-rouge">rejigger_oldest_widget</code> to the following:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">rejigger_oldest_widget</span><span class="p">(</span><span class="n">widgets</span><span class="p">,</span> <span class="n">max_age_years</span><span class="p">)</span>
<span class="n">widgets</span>
<span class="p">.</span><span class="nf">select</span><span class="p">(</span><span class="o">&</span><span class="ss">:working?</span><span class="p">)</span>
<span class="p">.</span><span class="nf">find</span> <span class="p">{</span> <span class="n">_1</span><span class="p">.</span><span class="nf">age_in_years</span> <span class="o"><=</span> <span class="n">max_age_years</span> <span class="p">}</span>
<span class="o">&</span><span class="p">.</span><span class="nf">rejigger</span>
<span class="o">&</span><span class="p">.</span><span class="nf">shuffle</span>
<span class="o">&</span><span class="p">.</span><span class="nf">shine</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Since <code class="language-plaintext highlighter-rouge">Enumerable#find</code> might return a <code class="language-plaintext highlighter-rouge">nil</code>, it will only be followed by <code class="language-plaintext highlighter-rouge">rejigger</code> when it produces a value. When it doesn’t, the computation stops at that point, and <code class="language-plaintext highlighter-rouge">rejigger_oldest_widget</code> returns <code class="language-plaintext highlighter-rouge">nil</code>.</p>
<p>Conveniently, it works with anything that could be called as a method, no matter the receiver (even <code class="language-plaintext highlighter-rouge">nil</code>). So, for example, say you had the following:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">ruffle_feathers</span><span class="p">(</span><span class="n">random_joe</span><span class="p">)</span>
<span class="k">return</span> <span class="k">if</span> <span class="p">(</span><span class="n">feathers</span> <span class="o">=</span> <span class="n">random_joe</span><span class="p">.</span><span class="nf">feathers</span><span class="p">).</span><span class="nf">nil?</span>
<span class="n">ruffled_feathers</span> <span class="o">=</span> <span class="n">annoyobot</span><span class="p">.</span><span class="nf">ruffle_feathers</span><span class="p">(</span><span class="n">feathers</span><span class="p">)</span>
<span class="n">annoyometer</span><span class="p">.</span><span class="nf">measure</span><span class="p">(</span><span class="n">ruffled_feathers</span><span class="p">)</span>
<span class="k">end</span>
</code></pre></div></div>
<p>You could easily write that as:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">ruffle_feathers</span><span class="p">(</span><span class="n">bird</span><span class="p">)</span>
<span class="n">random_joe</span>
<span class="p">.</span><span class="nf">feathers</span>
<span class="o">&</span><span class="p">.</span><span class="nf">then</span> <span class="p">{</span> <span class="n">annoyobot</span><span class="p">.</span><span class="nf">ruffle_feathers</span><span class="p">(</span><span class="n">_1</span><span class="p">)</span> <span class="p">}</span>
<span class="o">&</span><span class="p">.</span><span class="nf">then</span> <span class="p">{</span> <span class="n">annoyometer</span><span class="p">.</span><span class="nf">measure</span><span class="p">(</span><span class="n">_1</span><span class="p">)</span> <span class="p">}</span>
<span class="k">end</span>
</code></pre></div></div>
<p>I tend to favor this style. I don’t care about <code class="language-plaintext highlighter-rouge">ruffled_feathers</code> other than as an argument to <code class="language-plaintext highlighter-rouge">measure</code>. The chain of calls with the safe navigation operator makes that more evident (i.e., we want to go from a <code class="language-plaintext highlighter-rouge">random_joe</code> whose <code class="language-plaintext highlighter-rouge">feathers</code> can be ruffled to how ruffled their feathers were).</p>
<h2 id="maybe-we-can-discuss-further"><em>Maybe</em> we can discuss further</h2>
<p>Suppose you’re familiar with functional languages in the ML family. In that case, you’re probably making the connection I (and <a href="https://github.com/raganwald/andand">many</a> <a href="https://dry-rb.org/gems/dry-monads/1.0/">others</a>) have made: this is a lot like using the Maybe/Option monad. <code class="language-plaintext highlighter-rouge">&.</code> is like <code class="language-plaintext highlighter-rouge">map</code>/<code class="language-plaintext highlighter-rouge">fmap</code>. You can have the short-circuiting capabilities of <code class="language-plaintext highlighter-rouge">flatMap</code>/<code class="language-plaintext highlighter-rouge">bind</code> by producing a <code class="language-plaintext highlighter-rouge">nil</code> at any step of your computation.</p>
<p>You can easily find comments to that effect about any language with a safe navigation operator — often with a verdict like <em>“this is a hack”</em> or <em>“this is not as good as having a Monad.”</em> And they’re not wrong! Indeed, if you learn how Functors, Applicatives, and Monads work and what they make possible, you’ll probably be a little disappointed with how little <code class="language-plaintext highlighter-rouge">&.</code> accomplishes.</p>
<p>However, when terms like “monads,” “laws,” and “categories” show up in conversation, they mean a lot to the initiated and next to nothing to programmers with other backgrounds. So why do Haskell snobs poo-poo something which looks so helpful?</p>
<p>Since this is not a treatise on the narcissism of minor differences, nor another Monad tutorial, let’s focus on a practical scenario you can’t conveniently handle with <code class="language-plaintext highlighter-rouge">&.</code> alone.</p>
<h2 id="too-many-nils">Too many nils</h2>
<p>Sometimes you need to perform a computation with two or more values, and none of them can be <code class="language-plaintext highlighter-rouge">nil</code>. If any are <code class="language-plaintext highlighter-rouge">nil</code>, the final product will also be <code class="language-plaintext highlighter-rouge">nil</code>. So you write something like this:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">fix_global_warming</span><span class="p">(</span><span class="n">committed_nations</span><span class="p">,</span> <span class="n">ethical_companies</span><span class="p">,</span> <span class="n">conscientious_citizens</span><span class="p">)</span>
<span class="k">return</span> <span class="k">unless</span> <span class="n">committed_nations</span> <span class="o">&&</span> <span class="n">ethical_companies</span> <span class="o">&&</span> <span class="n">conscientious_citizens</span>
<span class="n">fix_it!</span><span class="p">(</span><span class="n">committed_nations</span><span class="p">,</span> <span class="n">ethical_companies</span><span class="p">,</span> <span class="n">conscientious_citizens</span><span class="p">)</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Presume you want something as declarative as chaining with <code class="language-plaintext highlighter-rouge">&.</code>. “Well, why not try <code class="language-plaintext highlighter-rouge">&.</code> itself?”, you think, ending up with:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">fix_global_warming</span><span class="p">(</span><span class="n">committed_nations</span><span class="p">,</span> <span class="n">ethical_companies</span><span class="p">,</span> <span class="n">conscientious_citizens</span><span class="p">)</span>
<span class="n">committed_nations</span><span class="o">&</span><span class="p">.</span><span class="nf">then</span> <span class="k">do</span> <span class="o">|</span><span class="n">nations</span><span class="o">|</span>
<span class="n">ethical_companies</span><span class="o">&</span><span class="p">.</span><span class="nf">then</span> <span class="k">do</span> <span class="o">|</span><span class="n">companies</span><span class="o">|</span>
<span class="n">conscientious_citizens</span><span class="o">&</span><span class="p">.</span><span class="nf">then</span> <span class="k">do</span> <span class="o">|</span><span class="n">citizens</span><span class="o">|</span>
<span class="n">fix_it!</span><span class="p">(</span><span class="n">nations</span><span class="p">,</span> <span class="n">companies</span><span class="p">,</span> <span class="n">citizens</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>It completely hides what the method does, and you might have trouble understanding that this is all for checking for the presence of values. The guard clause in the original version is <em>markedly</em> better.</p>
<p>How does Haskell solve this? After all, if writing code in that language were anything like the sample above, people wouldn’t think it’s so great. Fortunately, there are a few ways to make the core of the code clearer. We’ll go over some of them.</p>
<p>The first requires special syntax called <a href="https://en.m.wikibooks.org/wiki/Haskell/do_notation">“Do notation”</a>:</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- Starting with something like the Ruby code above</span>
<span class="n">fixGlobalWarming</span> <span class="o">::</span> <span class="kt">Maybe</span> <span class="kt">ComittedNations</span> <span class="o">-></span> <span class="kt">Maybe</span> <span class="kt">EthicalCompanies</span> <span class="o">-></span> <span class="kt">Maybe</span> <span class="kt">ConscientiousCitizens</span> <span class="o">-></span> <span class="kt">Maybe</span> <span class="kt">BetterPlanet</span>
<span class="n">fixGlobalWarming</span> <span class="n">committedNations</span> <span class="n">ethicalCompanies</span> <span class="n">conscientiousCitizens</span> <span class="o">=</span>
<span class="n">comittedNations</span> <span class="o">>>=</span>
<span class="nf">\</span><span class="n">nations</span> <span class="o">-></span> <span class="n">ethicalCompanies</span> <span class="o">>>=</span>
<span class="nf">\</span><span class="n">companies</span> <span class="o">-></span> <span class="n">conscientiousCitizens</span> <span class="o"><&></span>
<span class="nf">\</span><span class="n">citizens</span> <span class="o">-></span> <span class="n">pure</span> <span class="p">(</span><span class="n">fixIt</span> <span class="n">nations</span> <span class="n">companies</span> <span class="n">citizens</span><span class="p">)</span>
<span class="c1">-- A version with do notation</span>
<span class="n">fixGlobalWarming</span> <span class="n">committedNations</span> <span class="n">ethicalCompanies</span> <span class="n">conscientiousCitizens</span> <span class="o">=</span> <span class="kr">do</span>
<span class="n">nations</span> <span class="o"><-</span> <span class="n">committedNations</span>
<span class="n">companies</span> <span class="o"><-</span> <span class="n">ethicalCompanies</span>
<span class="n">citizens</span> <span class="o"><-</span> <span class="n">conscientiousCitizens</span>
<span class="n">pure</span> <span class="p">(</span><span class="n">fixIt</span> <span class="n">nations</span> <span class="n">companies</span> <span class="n">citizens</span><span class="p">)</span>
</code></pre></div></div>
<p>Since it’s syntax, we can only approximate it (<a href="https://dry-rb.org/gems/dry-monads/1.0/">dry-monads</a> has its take), which requires a bit of infrastructure. Considering that might prove excessive, we can also rely on it being an <code class="language-plaintext highlighter-rouge">Applicative Functor</code>, as well as on combinators that remove the boilerplate:</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- As an Applicative Functor</span>
<span class="n">fixGlobalWarming</span> <span class="n">committedNations</span> <span class="n">ethicalCompanies</span> <span class="n">conscientiousCitizens</span> <span class="o">=</span>
<span class="n">fixIt</span> <span class="o"><$></span> <span class="n">committedNations</span> <span class="o"><*></span> <span class="n">ethicalCompanies</span> <span class="o"><*></span> <span class="n">conscientiousCitizens</span>
<span class="c1">-- With a combinator</span>
<span class="n">fixGlobalWarming</span> <span class="o">=</span> <span class="n">liftM3</span> <span class="n">fixIt</span>
</code></pre></div></div>
<p>The Applicative version would never go well with Ruby. An operator soup is not most Rubyists’ favorite dish (even though it can be delicious!). So that leaves us with <code class="language-plaintext highlighter-rouge">liftM3</code>.</p>
<p>According to its documentation, what it does is “promote a function to a monad.” That means that you can take any function that takes three values and make it work with values in any monad, including Maybe. In that same vein, if you had a function that took two values, you would use <code class="language-plaintext highlighter-rouge">liftM2</code>; four, <code class="language-plaintext highlighter-rouge">liftM4</code>. And so on.</p>
<p>The reason for so many <code class="language-plaintext highlighter-rouge">liftM*</code> functions is that Haskell needs to account for the possibility each parameter is of a different type. That is, of course, not an issue we have with Ruby. We can, thus, define a similar combinator that allows us to work on any number of arguments:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">with_all_present</span><span class="p">(</span><span class="o">*</span><span class="n">values</span><span class="p">)</span>
<span class="k">yield</span> <span class="o">*</span><span class="n">values</span> <span class="k">if</span> <span class="n">values</span><span class="p">.</span><span class="nf">none?</span><span class="p">(</span><span class="o">&</span><span class="ss">:nil?</span><span class="p">)</span>
<span class="k">end</span>
</code></pre></div></div>
<p>This gives us a way to rewrite <code class="language-plaintext highlighter-rouge">fix_global_warming</code> as follows:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">fix_global_warming</span><span class="p">(</span><span class="n">committed_nations</span><span class="p">,</span> <span class="n">ethical_companies</span><span class="p">,</span> <span class="n">conscientious_citizens</span><span class="p">)</span>
<span class="n">with_all_present</span><span class="p">(</span><span class="n">committed_nations</span><span class="p">,</span> <span class="n">ethical_companies</span><span class="p">,</span> <span class="n">conscientious_citizens</span><span class="p">)</span> <span class="k">do</span>
<span class="n">fix_it</span><span class="p">(</span><span class="n">_1</span><span class="p">,</span> <span class="n">_2</span><span class="p">,</span> <span class="n">_3</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<h2 id="is-it-better">Is it better?</h2>
<p>As programmers, we’re always trying to find a good balance between conciseness and readability. It’s easy to go too far, and each individual cares about different things. Knowing that, it would be foolish to be assertive about any technique.</p>
<p>In my book, both <code class="language-plaintext highlighter-rouge">&.</code> and custom combinators give us tools to end up more confident and expressive code, unmarred by the fear of <code class="language-plaintext highlighter-rouge">nil</code>. They’re significant steps in the direction of robustness. And even if it’s true that neither will kill every <code class="language-plaintext highlighter-rouge">NoMethodError</code>, they’ll go a long way.</p>When people talk about working with Ruby, the usual spiel is about joy, humans at the center, MINASWAN, kittens, and all that sparkles. However, they rarely address the role of anxiety in our day to day. Or rather, of one specific concern: will I get a NoMethodError due to an unexpected nil?fp-ts overview: Error handling, the functional way (part 1)2020-09-24T10:15:00+00:002020-09-24T10:15:00+00:00http://troikatech.com/blog/2020/09/24/fp-ts-error-handling-the-functional-way<p>In most codebases, error-handling means <em>exceptions</em>. A team will carefully considering potential problems, then create sets of exceptions by extending some error class that will be used to signify something in the application domain went wrong.</p>
<p>The fact exceptions can come from deep within the call stack and bubble up very far from their point of origin often makes debugging them hard. They also affect code reuse, as every path that includes exception-throwing code also becomes exceptional — a fact that is usually hidden and forces (careful and caring) developers to perpetually keep documentation up-to-date at every level of the affected call stack to avoid surprising behavior.</p>
<p>Thinking about the matter might lead us to two conclusions:</p>
<ul>
<li>Not all exceptions are alike (“Out of memory” is not the same as a domain-specific error that can be tracked and handled);</li>
<li>We would benefit from treating errors less like landmines and more like integral parts of our code.</li>
</ul>
<p>These are not original thoughts. Programmers have tried finding ways to make error handling a top concern for decades, and a few different designs are present in mainstream(-ish) languages. Java has <a href="https://en.wikibooks.org/wiki/Java_Programming/Checked_Exceptions">checked exceptions</a>; Go has the infamous <code class="language-plaintext highlighter-rouge">if err != nil</code> pattern; Erlang APIs often return an <code class="language-plaintext highlighter-rouge">err</code> that you check before advancing.</p>
<p>These are often inconvenient enough that they lead either to sloppiness (errors being ignored or supressed under the assumption that they’re not important or severe enough) or confusion (the happy path becoming muddled by error checking code).</p>
<p>Modern statically-typed functional programming helps us with that by giving us structures and tools that act as a living document of what might wrong, let us defer handling errors, and make that happy path easy to write (and, more importantly, clear to read). One of these tools is <code class="language-plaintext highlighter-rouge">Either</code>.</p>
<h1 id="pushing-errors-to-the-forefront">Pushing errors to the forefront</h1>
<p>The key is making errors <em>values</em> like any other. Unlike relying on implicit behavior, we return an <code class="language-plaintext highlighter-rouge">Either<E, A></code>, which gives us a <em>left</em> branch (the <code class="language-plaintext highlighter-rouge">E</code> type, normally used to denote failures), and a <em>right</em> branch (the <code class="language-plaintext highlighter-rouge">A</code> type, for our desired outcomes).</p>
<p>That doesn’t imply we have to write tentative code, verifying at every step whether we have a failure or a success. Because <code class="language-plaintext highlighter-rouge">Either</code> favors its right branch, we are able to build data processing pipelines that operate safely, only reaching for the result at the latest possible moment. In practice, this means <em>we can’t forget to deal with failures</em>.</p>
<p>Here’s an example:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="p">{</span> <span class="nx">pipe</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">fp-ts/lib/pipeable</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="o">*</span> <span class="k">as</span> <span class="nx">E</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">fp-ts/lib/Either</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">Either</span> <span class="o">=</span> <span class="nx">E</span><span class="p">.</span><span class="nx">Either</span><span class="p">;</span>
<span class="kd">type</span> <span class="nx">Transaction</span> <span class="o">=</span> <span class="nx">unknown</span><span class="p">;</span>
<span class="kd">type</span> <span class="nx">Balance</span> <span class="o">=</span> <span class="nx">unknown</span><span class="p">;</span>
<span class="kd">type</span> <span class="nx">StatementError</span> <span class="o">=</span>
<span class="o">|</span> <span class="dl">"</span><span class="s2">invalid bank account</span><span class="dl">"</span>
<span class="o">|</span> <span class="dl">"</span><span class="s2">missing account number</span><span class="dl">"</span>
<span class="o">|</span> <span class="dl">"</span><span class="s2">malformed header</span><span class="dl">"</span>
<span class="o">|</span> <span class="dl">"</span><span class="s2">transaction can't be zeroes</span><span class="dl">"</span><span class="p">;</span>
<span class="kr">interface</span> <span class="nx">Statement</span> <span class="p">{</span>
<span class="k">readonly</span> <span class="nx">transactions</span><span class="p">:</span> <span class="nx">Transaction</span><span class="p">[];</span>
<span class="p">}</span>
<span class="kr">declare</span> <span class="kd">function</span> <span class="nx">parseBankStatement</span><span class="p">(</span><span class="nx">rawStatement</span><span class="p">:</span> <span class="kr">string</span><span class="p">):</span> <span class="nx">Either</span><span class="o"><</span><span class="nx">StatementError</span><span class="p">,</span> <span class="nx">Statement</span><span class="o">></span><span class="p">;</span>
<span class="kr">declare</span> <span class="kd">function</span> <span class="nx">validateTransactions</span><span class="p">(</span><span class="nx">transactions</span><span class="p">:</span> <span class="nx">Transaction</span><span class="p">[]):</span> <span class="nx">Either</span><span class="o"><</span><span class="nx">StatementError</span><span class="p">,</span> <span class="nx">Transaction</span><span class="p">[]</span><span class="o">></span><span class="p">;</span>
<span class="kr">declare</span> <span class="kd">function</span> <span class="nx">buildBalance</span><span class="p">(</span><span class="nx">transactions</span><span class="p">:</span> <span class="nx">Transaction</span><span class="p">[]):</span> <span class="nx">Balance</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">balanceFromRawStatement</span> <span class="o">=</span> <span class="p">(</span>
<span class="nx">rawStatement</span><span class="p">:</span> <span class="kr">string</span>
<span class="p">):</span> <span class="nx">Either</span><span class="o"><</span><span class="nx">StatementError</span><span class="p">,</span> <span class="nx">Balance</span><span class="o">></span> <span class="o">=></span>
<span class="nx">pipe</span><span class="p">(</span>
<span class="nx">parseBankStatement</span><span class="p">(</span><span class="nx">rawStatement</span><span class="p">),</span>
<span class="nx">E</span><span class="p">.</span><span class="nx">map</span><span class="p">((</span><span class="nx">s</span><span class="p">)</span> <span class="o">=></span> <span class="nx">s</span><span class="p">.</span><span class="nx">transactions</span><span class="p">),</span>
<span class="nx">E</span><span class="p">.</span><span class="nx">chain</span><span class="p">(</span><span class="nx">validateTransactions</span><span class="p">),</span>
<span class="nx">E</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">buildBalance</span><span class="p">)</span>
<span class="p">);</span>
</code></pre></div></div>
<p>We move data from step to step as if nothing had gone wrong. If <code class="language-plaintext highlighter-rouge">parseBankStatements</code> returns a <code class="language-plaintext highlighter-rouge">Left</code>, everything else is a no-op; if <code class="language-plaintext highlighter-rouge">validateTransactions</code> returns a <code class="language-plaintext highlighter-rouge">Left</code>, the last <code class="language-plaintext highlighter-rouge">E.map</code> will be skipped. Whatever happens, we don’t have to mix error-handling with the main logic.</p>
<h1 id="a-note-about-either-and-errors">A note about Either and <em>errors</em></h1>
<p>The <code class="language-plaintext highlighter-rouge">E</code> in <code class="language-plaintext highlighter-rouge">Either<E, A></code> can be whatever we want. It doesn’t even have to be an “error”, per se, though the default short-circuiting semantics associated with the left branch remain whatever type ends up being used.</p>
<h1 id="employing-either">Employing Either</h1>
<p>As with many things in fp-ts, we will use <code class="language-plaintext highlighter-rouge">pipe</code> often. This is mostly for type inferencing reasons, though it also helps us in keeping code declarative by not introducing bindings to hold intermediary steps.</p>
<h2 id="putting-things-in-eithers">Putting things in Eithers</h2>
<p>We use <code class="language-plaintext highlighter-rouge">right</code> to create a value in the right branch, <code class="language-plaintext highlighter-rouge">left</code> in the left branch:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="p">{</span> <span class="nx">pipe</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">fp-ts/lib/pipeable</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="o">*</span> <span class="k">as</span> <span class="nx">E</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">fp-ts/lib/Either</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">Either</span> <span class="o">=</span> <span class="nx">E</span><span class="p">.</span><span class="nx">Either</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">goodValue</span><span class="p">:</span> <span class="nx">Either</span><span class="o"><</span><span class="nb">Error</span><span class="p">,</span> <span class="kr">string</span><span class="o">></span> <span class="o">=</span> <span class="nx">E</span><span class="p">.</span><span class="nx">right</span><span class="p">(</span><span class="dl">"</span><span class="s2">Good</span><span class="dl">"</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">badValue</span><span class="p">:</span> <span class="nx">Either</span><span class="o"><</span><span class="nb">Error</span><span class="p">,</span> <span class="kr">string</span><span class="o">></span> <span class="o">=</span> <span class="nx">E</span><span class="p">.</span><span class="nx">left</span><span class="p">(</span><span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="dl">"</span><span class="s2">Bad</span><span class="dl">"</span><span class="p">));</span>
</code></pre></div></div>
<h2 id="working-with-eithers-when-we-have-rights">Working with Eithers when we have Rights</h2>
<p>We can use <code class="language-plaintext highlighter-rouge">map</code> (from Functor) or <code class="language-plaintext highlighter-rouge">chain</code> (from Monad). The main practical difference is that the former allows us to transform the value while keeping it in the right branch, and the latter confers us the power to decide whether to keep on the right or move to the left (i.e. we can decide a computation should be treated as an error from then on).</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>const betterValue = pipe(
goodValue,
E.map(value => `${value} is now 'better'`)
); // this is a changed 'right'
const worseValue = pipe(
goodValue,
E.chain(value => E.left(new Error(`Nothing can be ${value} in 2020`)))
); // this is now a 'left'
</code></pre></div></div>
<h2 id="working-with-eithers-when-we-have-lefts">Working with Eithers when we have Lefts</h2>
<p>We can modify the error using <code class="language-plaintext highlighter-rouge">mapLeft</code>:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">crypticError</span><span class="p">:</span> <span class="nx">Either</span><span class="o"><</span><span class="kr">number</span><span class="p">,</span> <span class="kr">string</span><span class="o">></span> <span class="o">=</span> <span class="nx">pipe</span><span class="p">(</span>
<span class="nx">worseValue</span><span class="p">,</span>
<span class="nx">E</span><span class="p">.</span><span class="nx">mapLeft</span><span class="p">((</span><span class="nx">err</span><span class="p">)</span> <span class="o">=></span> <span class="nx">err</span><span class="p">.</span><span class="nx">message</span><span class="p">.</span><span class="nx">length</span><span class="p">)</span>
<span class="p">);</span>
</code></pre></div></div>
<p>Provide alternative values:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">improvedValue</span> <span class="o">=</span> <span class="nx">pipe</span><span class="p">(</span>
<span class="nx">worseValue</span><span class="p">,</span>
<span class="nx">E</span><span class="p">.</span><span class="nx">alt</span><span class="p">(()</span> <span class="o">=></span> <span class="nx">E</span><span class="p">.</span><span class="nx">right</span><span class="p">(</span><span class="dl">"</span><span class="s2">Back to 2015</span><span class="dl">"</span><span class="p">))</span>
<span class="p">);</span>
</code></pre></div></div>
<p>Provide alternative values while peeking at the error:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">optimisticValue</span> <span class="o">=</span> <span class="nx">pipe</span><span class="p">(</span>
<span class="nx">worseValue</span><span class="p">,</span>
<span class="nx">E</span><span class="p">.</span><span class="nx">orElse</span><span class="p">((</span><span class="nx">err</span><span class="p">)</span> <span class="o">=></span> <span class="nx">E</span><span class="p">.</span><span class="nx">right</span><span class="p">(</span><span class="s2">`</span><span class="p">${</span><span class="nx">err</span><span class="p">.</span><span class="nx">message</span><span class="p">}</span><span class="s2">. But there's always 2021.`</span><span class="p">))</span>
<span class="p">);</span>
</code></pre></div></div>
<p>Note: we don’t necessarily have to provide a <code class="language-plaintext highlighter-rouge">right</code>. We can map an error to another error, for instance.</p>
<h2 id="working-with-existing-code-that-might-throw-exceptions">Working with existing code that might throw exceptions</h2>
<p>TypeScript operates under the rules of JavaScript, and our application will inevitably integrate with third-party code that creates exceptions. We could use <code class="language-plaintext highlighter-rouge">try...catch</code> and do our own wrapping, but <code class="language-plaintext highlighter-rouge">Either.tryCatch</code> already takes care of that pattern for us:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">safeParseJson</span> <span class="o">=</span> <span class="p">(</span><span class="nx">str</span><span class="p">:</span> <span class="kr">string</span><span class="p">):</span> <span class="nx">Either</span><span class="o"><</span><span class="nb">Error</span><span class="p">,</span> <span class="nx">unknown</span><span class="o">></span> <span class="o">=></span>
<span class="nx">E</span><span class="p">.</span><span class="nx">tryCatch</span><span class="o"><</span><span class="nb">Error</span><span class="p">,</span> <span class="nx">unknown</span><span class="o">></span><span class="p">(</span>
<span class="p">()</span> <span class="o">=></span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">str</span><span class="p">),</span>
<span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="o">=></span> <span class="p">(</span><span class="nx">err</span> <span class="k">instanceof</span> <span class="nb">Error</span> <span class="p">?</span> <span class="nx">err</span> <span class="p">:</span> <span class="nb">Error</span><span class="p">(</span><span class="dl">"</span><span class="s2">unexpected error when parsing json</span><span class="dl">"</span><span class="p">))</span>
<span class="p">);</span>
<span class="kd">const</span> <span class="nx">yayJson</span> <span class="o">=</span> <span class="nx">safeParseJson</span><span class="p">(</span><span class="dl">"</span><span class="s2">}</span><span class="dl">"</span><span class="p">);</span>
</code></pre></div></div>
<h2 id="taking-things-out-of-eithers">Taking things out of Eithers</h2>
<p>It’s not possible to reach into an Either and take the value or the error out. We have to help the compiler understand what is actually possible based on the runtime value we have at hand.</p>
<p>One way to do it is using the type guards defined in fp-ts’s Either:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="nx">E</span><span class="p">.</span><span class="nx">isLeft</span><span class="p">(</span><span class="nx">worseValue</span><span class="p">))</span> <span class="p">{</span>
<span class="c1">// worseValue.left will be available</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="c1">// worseValue.right will be available</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">E</span><span class="p">.</span><span class="nx">isRight</span><span class="p">(</span><span class="nx">worseValue</span><span class="p">))</span> <span class="p">{</span>
<span class="c1">// worseValue.right will be available</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="c1">// worseValue.left will be available</span>
<span class="p">}</span>
</code></pre></div></div>
<p>This may be useful in some situations, but it won’t fit with our pipelines as well as the alternatives. Instead, we should use the helper functions defined in Either</p>
<h3 id="getorelse">getOrElse</h3>
<p><code class="language-plaintext highlighter-rouge">getOrElse</code> requires us to define a way to build an <code class="language-plaintext highlighter-rouge">A</code> from an <code class="language-plaintext highlighter-rouge">E</code>:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">mehValue</span> <span class="o">=</span> <span class="nx">pipe</span><span class="p">(</span>
<span class="nx">worseValue</span><span class="p">,</span>
<span class="nx">E</span><span class="p">.</span><span class="nx">getOrElse</span><span class="p">((</span><span class="nx">err</span><span class="p">)</span> <span class="o">=></span> <span class="s2">`I used to be </span><span class="p">${</span><span class="nx">err</span><span class="p">}</span><span class="s2">. Now I'm free`</span><span class="p">)</span>
<span class="p">);</span>
</code></pre></div></div>
<h3 id="fold">fold</h3>
<p><code class="language-plaintext highlighter-rouge">fold</code> requires us to provide mappings from <code class="language-plaintext highlighter-rouge">E</code> and <code class="language-plaintext highlighter-rouge">A</code> to a common type <code class="language-plaintext highlighter-rouge">B</code>:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">answer</span> <span class="o">=</span> <span class="nx">pipe</span><span class="p">(</span>
<span class="nx">improvedValue</span><span class="p">,</span>
<span class="nx">E</span><span class="p">.</span><span class="nx">fold</span><span class="p">(</span>
<span class="p">()</span> <span class="o">=></span> <span class="mi">42</span><span class="p">,</span>
<span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="o">=></span> <span class="nx">value</span><span class="p">.</span><span class="nx">length</span>
<span class="p">)</span>
<span class="p">);</span>
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">fold</code> is more powerful than <code class="language-plaintext highlighter-rouge">getOrElse</code>, because you can perform transformations (i.e. <code class="language-plaintext highlighter-rouge">getOrElse</code> requires you to provide a value of the same type <code class="language-plaintext highlighter-rouge">A</code> as in the <code class="language-plaintext highlighter-rouge">Either</code>, while <code class="language-plaintext highlighter-rouge">fold</code> allows you to return a <code class="language-plaintext highlighter-rouge">B</code>).</p>
<h1 id="variations-defined-in-the-library">Variations <a href="https://gcanti.github.io/fp-ts/modules/">defined in the library</a>:</h1>
<p>Either is useful in other contexts — when performing IO, when performing async computations, when performing computations within a context/environment, when performing async computations within a context/environment, et cetera —, and fp-ts ships with a few different monad stacks that include it:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">IOEither<E, A></code></li>
<li><code class="language-plaintext highlighter-rouge">TaskEither<E, A></code></li>
<li><code class="language-plaintext highlighter-rouge">ReaderEither<E, A></code></li>
<li><code class="language-plaintext highlighter-rouge">ReaderTaskEither<R, E, A></code></li>
<li><code class="language-plaintext highlighter-rouge">StateReaderTaskEither<S, R, E, A></code></li>
</ul>
<h1 id="coming-soon-in-blogs-code-for-this-is-the-last-post-for-a-while">Coming soon (in blogs, code for “this is the last post for a while”)</h1>
<p>In part 2, we’ll talk about calling functions when you have more than one <code class="language-plaintext highlighter-rouge">Either</code>, accumulating errors (instead of short-circuiting), pulling things inside-out, and writing confident and expressive code using <code class="language-plaintext highlighter-rouge">Either</code>. Stay tuned.</p>In most codebases, error-handling means exceptions. A team will carefully considering potential problems, then create sets of exceptions by extending some error class that will be used to signify something in the application domain went wrong.A Tour of TypeScript as a Typed Functional Programming Language2020-09-11T16:25:00+00:002020-09-11T16:25:00+00:00http://troikatech.com/blog/2020/09/11/a-tour-of-typescript-as-a-statically-typed-fp-lang<p><em>(edited for clarity in 2020-09-11T00:28:15Z)</em></p>
<p>If you’ve been curious about (or studying) statically typed functional programming for a while, I bet you’ve asked yourself these questions:</p>
<ul>
<li>How much do I have to learn to apply it successfully?</li>
<li>Will I ever stop being surprised by how much I don’t know?</li>
<li>Can I get paid to work in that style?</li>
</ul>
<p>Digging deeper and becoming more knowledgeable is a fun effort by itself. The third question is more delicate, nuanced, and probably anxiety-inducing than the first two: Haskell (or Haskell-adjacent) jobs are scarce, and your best bet is trying to land a Scala job in an FP-friendly organization.</p>
<p>But there’s a dearth of Scala jobs, as well, and most of them are in the land of data science. Instead of growing despondent, here’s my proposition: the easiest path to marrying statically-typed functional programming and your source of income is to go extremely mainstream and use TypeScript.</p>
<h2 id="does-typescript-pass-muster">Does TypeScript pass muster?</h2>
<p>Yes! You don’t even have to squint that hard.</p>
<p>TypeScript gives you enough tools to make illegal states unrepresentable at compile time, and its type system, by virtue of having to model JavaScript with its every wart, is very interesting and powerful. Its features include:</p>
<ul>
<li>First-class functions;</li>
<li><a href="https://www.typescriptlang.org/docs/handbook/generics.html">Parametric polymorphism</a>, with rich constructs such as conditional types;</li>
<li>Algebraic Data Types.</li>
</ul>
<p>Expressing these concepts might not be as succint as in Haskell, PureScript or Elm, but it’s possible with tolerable noise, resulting in the same compounding benefits you would find in friendlier environs.</p>
<p>What follows is an overview of the basics of using TypeScript as a Haskell impersonator. Some of the examples will rely on the <a href="https://gcanti.github.io/fp-ts/">fp-ts</a> ecosystem.</p>
<h2 id="thinking-in-transformations">Thinking in transformations</h2>
<p>One major way FP-style has infected the mainstream is in computations that are built as chainable expressions. In JavaScript, for instance, it would be quite natural to write something like the code below:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">animals</span> <span class="o">=</span> <span class="p">[</span>
<span class="p">{</span> <span class="na">name</span><span class="p">:</span> <span class="dl">"</span><span class="s2">giraffe</span><span class="dl">"</span><span class="p">,</span> <span class="na">type</span><span class="p">:</span> <span class="dl">"</span><span class="s2">mammal</span><span class="dl">"</span> <span class="p">},</span>
<span class="p">{</span> <span class="na">name</span><span class="p">:</span> <span class="dl">"</span><span class="s2">elephant</span><span class="dl">"</span><span class="p">,</span> <span class="na">type</span><span class="p">:</span> <span class="dl">"</span><span class="s2">mammal</span><span class="dl">"</span> <span class="p">},</span>
<span class="p">{</span> <span class="na">name</span><span class="p">:</span> <span class="dl">"</span><span class="s2">crocodile</span><span class="dl">"</span><span class="p">,</span> <span class="na">type</span><span class="p">:</span> <span class="dl">"</span><span class="s2">reptile</span><span class="dl">"</span> <span class="p">},</span>
<span class="p">{</span> <span class="na">name</span><span class="p">:</span> <span class="dl">"</span><span class="s2">emu</span><span class="dl">"</span><span class="p">,</span> <span class="na">type</span><span class="p">:</span> <span class="dl">"</span><span class="s2">bird</span><span class="dl">"</span> <span class="p">},</span>
<span class="p">{</span> <span class="na">name</span><span class="p">:</span> <span class="dl">"</span><span class="s2">gecko</span><span class="dl">"</span><span class="p">,</span> <span class="na">type</span><span class="p">:</span> <span class="dl">"</span><span class="s2">reptile</span><span class="dl">"</span> <span class="p">}</span>
<span class="p">];</span>
<span class="kd">const</span> <span class="nx">reptilesWithG</span> <span class="o">=</span> <span class="nx">animals</span>
<span class="p">.</span><span class="nx">filter</span><span class="p">(</span><span class="nx">a</span> <span class="o">=></span> <span class="nx">a</span><span class="p">.</span><span class="kd">class</span> <span class="o">===</span> <span class="dl">"</span><span class="s2">reptile</span><span class="dl">"</span><span class="p">)</span>
<span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">a</span> <span class="o">=></span> <span class="nx">a</span><span class="p">.</span><span class="nx">name</span><span class="p">)</span>
<span class="p">.</span><span class="nx">filter</span><span class="p">(</span><span class="nx">name</span> <span class="o">=></span> <span class="nx">name</span><span class="p">.</span><span class="nx">startsWith</span><span class="p">(</span><span class="dl">"</span><span class="s2">g</span><span class="dl">"</span><span class="p">));</span>
</code></pre></div></div>
<p>It has a lot of what’s good about functional programming. Data pipelines, higher-order functions, composability. But why solving problems using that approach interesting?</p>
<p>One way to view it is that it focuses on the <em>what</em> instead of on the <em>how</em>. It doesn’t introduce bindings at the same level as the code you’re interested in — you don’t care about the intermediate steps between <code class="language-plaintext highlighter-rouge">animals</code> and <code class="language-plaintext highlighter-rouge">reptilesWithG</code>. Existing higher-order functions (<code class="language-plaintext highlighter-rouge">map</code> and <code class="language-plaintext highlighter-rouge">filter</code>) take you to your destination.</p>
<p>That immediately provides a big benefit: a single expression can be refactored easily. It would be straightforward to fuse the two filters. Extracting a function taking <code class="language-plaintext highlighter-rouge">animals</code> and calling it in place could be done in a pinch.</p>
<p>Data transformation pipelines rely on <em>composability</em> — combining functions that do part of a job in order to build richer behavior. This in turn requires each part to be referentially transparent. Types only enhance these characteristics, as each function will be mechanically verified by the compiler, and pipelines will be correctly connected when the compiler is happy.</p>
<p>There are different functional programming libraries for TypeScript, and each implements its pipelining functions. If you use fp-ts, <code class="language-plaintext highlighter-rouge">pipe</code> (and <code class="language-plaintext highlighter-rouge">flow</code>) will be your bread and butter:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="k">import</span> <span class="p">{</span> <span class="nx">pipe</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">fp-ts/lib/pipeable</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="o">*</span> <span class="k">as</span> <span class="nx">A</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">fp-ts/lib/Array</span><span class="dl">"</span><span class="p">;</span>
<span class="kr">interface</span> <span class="nx">Animal</span> <span class="p">{</span>
<span class="nl">name</span><span class="p">:</span> <span class="kr">string</span><span class="p">;</span>
<span class="nl">type</span><span class="p">:</span> <span class="kr">string</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">const</span> <span class="nx">animals</span><span class="p">:</span> <span class="nx">Animal</span><span class="p">[]</span> <span class="o">=</span> <span class="p">[</span>
<span class="p">{</span> <span class="na">name</span><span class="p">:</span> <span class="dl">"</span><span class="s2">giraffe</span><span class="dl">"</span><span class="p">,</span> <span class="na">type</span><span class="p">:</span> <span class="dl">"</span><span class="s2">mammal</span><span class="dl">"</span> <span class="p">},</span>
<span class="p">{</span> <span class="na">name</span><span class="p">:</span> <span class="dl">"</span><span class="s2">elephant</span><span class="dl">"</span><span class="p">,</span> <span class="na">type</span><span class="p">:</span> <span class="dl">"</span><span class="s2">mammal</span><span class="dl">"</span> <span class="p">},</span>
<span class="p">{</span> <span class="na">name</span><span class="p">:</span> <span class="dl">"</span><span class="s2">crocodile</span><span class="dl">"</span><span class="p">,</span> <span class="na">type</span><span class="p">:</span> <span class="dl">"</span><span class="s2">reptile</span><span class="dl">"</span> <span class="p">},</span>
<span class="p">{</span> <span class="na">name</span><span class="p">:</span> <span class="dl">"</span><span class="s2">emu</span><span class="dl">"</span><span class="p">,</span> <span class="na">type</span><span class="p">:</span> <span class="dl">"</span><span class="s2">bird</span><span class="dl">"</span> <span class="p">},</span>
<span class="p">{</span> <span class="na">name</span><span class="p">:</span> <span class="dl">"</span><span class="s2">gecko</span><span class="dl">"</span><span class="p">,</span> <span class="na">type</span><span class="p">:</span> <span class="dl">"</span><span class="s2">reptile</span><span class="dl">"</span> <span class="p">}</span>
<span class="p">];</span>
<span class="kd">const</span> <span class="nx">reptilesWithG</span> <span class="o">=</span> <span class="nx">pipe</span><span class="p">(</span>
<span class="nx">animals</span><span class="p">,</span>
<span class="nx">A</span><span class="p">.</span><span class="nx">filter</span><span class="p">(</span><span class="nx">a</span> <span class="o">=></span> <span class="nx">a</span><span class="p">.</span><span class="kd">class</span> <span class="o">===</span> <span class="dl">"</span><span class="s2">reptile</span><span class="dl">"</span> <span class="o">&&</span> <span class="nx">a</span><span class="p">.</span><span class="nx">name</span><span class="p">.</span><span class="nx">startWith</span><span class="p">(</span><span class="dl">"</span><span class="s2">g</span><span class="dl">"</span><span class="p">)),</span>
<span class="nx">A</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">a</span> <span class="o">=></span> <span class="nx">a</span><span class="p">.</span><span class="nx">name</span><span class="p">)</span>
<span class="p">);</span>
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">pipe</code> passes the results of one step as an argument to the next step. <code class="language-plaintext highlighter-rouge">animals</code> will be the input for <code class="language-plaintext highlighter-rouge">A.filter</code>, and the result of said filtering will be the input for <code class="language-plaintext highlighter-rouge">A.map</code>.</p>
<p>This way of writing the code detaches the Array transformation functions from functions in the <code class="language-plaintext highlighter-rouge">animals</code> object. This is good: not only it makes steps recombinable, it also helps cement the idea that sequences of transformations are not restricted to things in collections. fp-ts makes it easy to do the same thing with asynchronous computations, for instance:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="o">*</span> <span class="k">as</span> <span class="nx">T</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">fp-ts/lib/Task</span><span class="dl">"</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">addPopulation</span> <span class="o">=</span> <span class="p">(</span><span class="nx">animal</span><span class="p">:</span> <span class="nx">Animal</span><span class="p">):</span> <span class="nx">Task</span><span class="o"><</span><span class="nx">AnimalWithPopulation</span><span class="o">></span> <span class="o">=></span> <span class="nx">pipe</span><span class="p">(</span>
<span class="nx">fetchPopulation</span><span class="p">(</span><span class="nx">animal</span><span class="p">.</span><span class="nx">name</span><span class="p">),</span>
<span class="nx">T</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">population</span> <span class="o">=></span> <span class="p">{</span> <span class="p">...</span><span class="nx">animal</span><span class="p">,</span> <span class="nx">population</span> <span class="p">})</span>
<span class="p">);</span>
</code></pre></div></div>
<p>It also will aid in building your intuitions for the similarities between different structures and computational contexts. <code class="language-plaintext highlighter-rouge">A.map</code> and <code class="language-plaintext highlighter-rouge">T.map</code> are possible because <code class="language-plaintext highlighter-rouge">Array</code> and <code class="language-plaintext highlighter-rouge">Task</code> are both <code class="language-plaintext highlighter-rouge">Functors</code>, for instance, but you don’t even need to know that for them to be useful. Understanding that changing data in <code class="language-plaintext highlighter-rouge">Task</code> requires <code class="language-plaintext highlighter-rouge">map</code> and changing data in <code class="language-plaintext highlighter-rouge">Array</code> also requires <code class="language-plaintext highlighter-rouge">map</code> will possibly help in in intuiting that <code class="language-plaintext highlighter-rouge">Either</code> might also require <code class="language-plaintext highlighter-rouge">map</code>.</p>
<h2 id="immutability">Immutability</h2>
<p>JavaScript is not immutable by default. A few tools exist (<code class="language-plaintext highlighter-rouge">Object.freeze</code>, non-writable properties) to avoid mutation at runtime, but they usually restrict shallow mutations only, and require discipline when dealing with data (e.g. you can’t forget a call to <code class="language-plaintext highlighter-rouge">freeze</code>).</p>
<p>TypeScript gives you a few tools to avoid the temptation of changing data in place. You can, for instance, declare interface fields as <code class="language-plaintext highlighter-rouge">readonly</code>:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">interface</span> <span class="nx">Animal</span> <span class="p">{</span>
<span class="k">readonly</span> <span class="nx">name</span><span class="p">:</span> <span class="kr">string</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">const</span> <span class="nx">animal</span> <span class="o">=</span> <span class="p">{</span> <span class="na">name</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Tiger</span><span class="dl">"</span> <span class="p">};</span>
<span class="nx">animal</span><span class="p">.</span><span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Liger</span><span class="dl">"</span><span class="p">;</span> <span class="c1">// error TS2540: Cannot assign to 'name' because it is a read-only property.</span>
</code></pre></div></div>
<p>As well as declaring Arrays as <code class="language-plaintext highlighter-rouge">readonly</code> (or <code class="language-plaintext highlighter-rouge">ReadonlyArray<T></code>):</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">answers</span><span class="p">:</span> <span class="k">readonly</span> <span class="kr">string</span><span class="p">[]</span> <span class="o">=</span> <span class="p">[</span><span class="dl">"</span><span class="s2">foo</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">bar</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">baz</span><span class="dl">"</span><span class="p">];</span>
<span class="nx">answers</span><span class="p">[</span><span class="mi">42</span><span class="p">]</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">what is the question?</span><span class="dl">"</span><span class="p">;</span> <span class="c1">// error TS2542: Index signature in type 'readonly string[]' only permits reading.</span>
</code></pre></div></div>
<p>And function parameters as <code class="language-plaintext highlighter-rouge">Readonly</code>:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">interface</span> <span class="nx">Room</span> <span class="p">{</span>
<span class="nl">name</span><span class="p">:</span> <span class="kr">string</span><span class="p">;</span> <span class="c1">// not readonly</span>
<span class="nl">occupancy</span><span class="p">:</span> <span class="kr">number</span><span class="p">;</span> <span class="c1">// not readonly</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">changeOccupancy</span><span class="p">(</span><span class="nx">room</span><span class="p">:</span> <span class="nb">Readonly</span><span class="o"><</span><span class="nx">Room</span><span class="o">></span><span class="p">):</span> <span class="nx">Room</span> <span class="p">{</span>
<span class="nx">room</span><span class="p">.</span><span class="nx">occupancy</span> <span class="o">=</span> <span class="mi">110</span><span class="p">;</span> <span class="c1">// error TS2540: Cannot assign to 'occupancy' because it is a read-only property.</span>
<span class="k">return</span> <span class="nx">room</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>You can even <a href="https://www.sitepoint.com/compile-time-immutability-in-typescript/">make a type recursively immutable</a>.</p>
<h2 id="type-system-features">Type system features</h2>
<p>TypeScript has a structural type system, instead of a nominal one. If you have an <code class="language-plaintext highlighter-rouge">interface Friend { name: string; age: 42; }</code> and a <code class="language-plaintext highlighter-rouge">function isAdult(subject: { age: number }): boolean</code>, passing a <code class="language-plaintext highlighter-rouge">Friend</code> to <code class="language-plaintext highlighter-rouge">isAdult</code> will work, because it requires <code class="language-plaintext highlighter-rouge">age: number</code> and <code class="language-plaintext highlighter-rouge">Friend</code> has an <code class="language-plaintext highlighter-rouge">age: number</code>.</p>
<p>This begets interesting modelling tools and capabilities. Remember <code class="language-plaintext highlighter-rouge">addPopulation</code>? It took a type called <code class="language-plaintext highlighter-rouge">AnimalWithPopulation</code>. Here’s one way you could define it in TypeScript:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">interface</span> <span class="nx">AnimalWithPopulation</span> <span class="kd">extends</span> <span class="nx">Animal</span> <span class="p">{</span>
<span class="nl">population</span><span class="p">:</span> <span class="kr">number</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>And here’s another:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">type</span> <span class="nx">AnimalWithPopulation</span> <span class="o">=</span> <span class="nx">Animal</span> <span class="o">&</span> <span class="p">{</span>
<span class="na">population</span><span class="p">:</span> <span class="kr">number</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div></div>
<p>It might look like a case of “six of one, half a dozen of the other”, but isn’t. What the second form gives you is a way to <a href="https://www.typescriptlang.org/docs/handbook/advanced-types.html#intersection-types">augment types</a> (TypeScript calls them <em>intersection types</em>) without creating class hierarchies, wrappers or decorators.</p>
<p>Say you have an e-commerce site that has some functionality only available for registered customers. A registered customer must have an email and an address, and the presence of an email and the presence of an address are concepts already defined in other places. You could define it as so:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">type</span> <span class="nx">Customer</span> <span class="o">=</span> <span class="p">{</span> <span class="na">lastViewedPage</span><span class="p">:</span> <span class="kr">string</span> <span class="p">};</span>
<span class="kd">type</span> <span class="nx">HasEmail</span> <span class="o">=</span> <span class="p">{</span> <span class="na">email</span><span class="p">:</span> <span class="kr">string</span> <span class="p">};</span>
<span class="kd">type</span> <span class="nx">HasAddress</span> <span class="o">=</span> <span class="p">{</span> <span class="na">address</span><span class="p">:</span> <span class="nx">Address</span> <span class="p">};</span>
<span class="kd">type</span> <span class="nx">HasName</span> <span class="o">=</span> <span class="p">{</span> <span class="na">firstName</span><span class="p">:</span> <span class="kr">string</span><span class="p">,</span> <span class="na">lastName</span><span class="p">:</span> <span class="kr">string</span> <span class="p">};</span>
<span class="kd">type</span> <span class="nx">RegisteredCustomer</span> <span class="o">=</span> <span class="nx">Customer</span> <span class="o">&</span> <span class="nx">HasName</span> <span class="o">&</span> <span class="nx">HasEmail</span> <span class="o">&</span> <span class="nx">HasAddress</span><span class="p">;</span>
</code></pre></div></div>
<p>Admittedly this is a contrived example, but I hope it illustrates an interesting possibility: you can build your domain model in such a way that the code acts only on the pieces it cares about:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">generateLabel</span><span class="p">(</span><span class="nx">recipient</span><span class="p">:</span> <span class="nx">HasName</span> <span class="o">&</span> <span class="nx">HasAddress</span><span class="p">):</span> <span class="nx">PackageLabel</span> <span class="p">{</span>
<span class="c1">// ...</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">prepareShipment</span><span class="p">(</span><span class="nx">recipient</span><span class="p">:</span> <span class="nx">HasName</span> <span class="o">&</span> <span class="nx">HasEmail</span> <span class="o">&</span> <span class="nx">HasAddress</span><span class="p">):</span> <span class="nx">Shipment</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">label</span> <span class="o">=</span> <span class="nx">generateLabel</span><span class="p">(</span><span class="nx">recipient</span><span class="p">);</span>
<span class="c1">// ...</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Another interesting aspect of its type system are literal types:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">type</span> <span class="nx">John</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">John</span><span class="dl">"</span><span class="p">;</span>
<span class="kd">type</span> <span class="nx">Role</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">admin</span><span class="dl">"</span> <span class="o">|</span> <span class="dl">"</span><span class="s2">guest</span><span class="dl">"</span> <span class="o">|</span> <span class="dl">"</span><span class="s2">regular</span><span class="dl">"</span> <span class="o">|</span> <span class="dl">"</span><span class="s2">manager</span><span class="dl">"</span><span class="p">;</span>
<span class="kd">type</span> <span class="nx">Floor</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">|</span> <span class="mi">2</span> <span class="o">|</span> <span class="mi">3</span> <span class="o">|</span> <span class="mi">4</span> <span class="o">|</span> <span class="mi">5</span> <span class="o">|</span> <span class="mi">6</span><span class="p">;</span>
</code></pre></div></div>
<p>Code specifying <code class="language-plaintext highlighter-rouge">Role</code> or <code class="language-plaintext highlighter-rouge">Floor</code> will only take those literals. You can’t pass any <code class="language-plaintext highlighter-rouge">number</code> as a Floor, or any <code class="language-plaintext highlighter-rouge">string</code> as a Role (though there’s a way to <a href="https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-differentiating-types">narrow those types to the subset specified in the union</a>). <code class="language-plaintext highlighter-rouge">John</code> can only be “John”.</p>
<p>When combining literal types with objects and unions, we get Algebraic Data Types.</p>
<h2 id="making-impossible-states-unrepresentable-modelling-with-algebraic-data-types-adts">Making impossible states unrepresentable: modelling with Algebraic Data Types (ADTs)</h2>
<p>Take the common necessity of fetching data asynchronously. A desirable UX can be described in four scenarios:</p>
<ul>
<li>While fetching the data, you would like to display a loading indicator;</li>
<li>When you have data, you would like to render it;</li>
<li>When fetching fails for some reason, you would want to display the error in the UI;</li>
<li>When refreshing data, you would like to display the loading indicator over the existing data;</li>
</ul>
<p>You might, then, create this model:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">interface</span> <span class="nx">PageData</span><span class="o"><</span><span class="nx">T</span><span class="o">></span> <span class="p">{</span>
<span class="na">isLoading</span><span class="p">:</span> <span class="nx">boolean</span><span class="p">;</span>
<span class="nl">data</span><span class="p">?:</span> <span class="nx">T</span><span class="p">;</span>
<span class="nl">error</span><span class="p">?:</span> <span class="nb">Error</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>with these conditionals:</p>
<ul>
<li>if <code class="language-plaintext highlighter-rouge">data</code> is present, render it;</li>
<li>if <code class="language-plaintext highlighter-rouge">isLoading</code> is true, render the loading indicator (if <code class="language-plaintext highlighter-rouge">data</code> is also present, render it over the rendered data);</li>
<li>if <code class="language-plaintext highlighter-rouge">error</code> is present, render the error.</li>
</ul>
<p>It looks fine at a first glance, but it’s not bulletprof. One day, <code class="language-plaintext highlighter-rouge">data</code> and <code class="language-plaintext highlighter-rouge">error</code> could both be present by mistake, which could then result in the wrong UI because of error-prone conditionals like <code class="language-plaintext highlighter-rouge">if (!isLoading && !error && data) { ... }</code>.</p>
<p>By thinking things through, it becomes clear that some of the data is only relevant in some of the states of the fetching process. <code class="language-plaintext highlighter-rouge">error</code> is only relevant when there’s an <code class="language-plaintext highlighter-rouge">Error</code>, and <code class="language-plaintext highlighter-rouge">data</code> is only relevant when actual <code class="language-plaintext highlighter-rouge">data</code> exists or a refresh is happening. If neither is present, the initial loading is happening.</p>
<p>You <em>could</em> write tests to keep these in check, but <a href="https://wiki.c2.com/?TestsCantProveTheAbsenceOfBugs">tests can’t prove the absence of bugs</a>. If a mistake not covered by them got introduced, it would only be found during runtime (possibly in production). You should, instead, leverage the compiler to ensure you get what you need at the right time, and <em>only</em> what you need:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">interface</span> <span class="nx">FetchingData</span> <span class="p">{</span>
<span class="nl">_tag</span><span class="p">:</span> <span class="dl">"</span><span class="s2">FETCHING_DATA</span><span class="dl">"</span><span class="p">;</span>
<span class="p">};</span>
<span class="kr">interface</span> <span class="nx">FetchedData</span><span class="o"><</span><span class="nx">T</span><span class="o">></span> <span class="p">{</span>
<span class="na">_tag</span><span class="p">:</span> <span class="dl">"</span><span class="s2">FETCHED_DATA</span><span class="dl">"</span><span class="p">;</span>
<span class="nl">data</span><span class="p">:</span> <span class="nx">T</span><span class="p">;</span>
<span class="p">}</span>
<span class="kr">interface</span> <span class="nx">FetchingFailed</span> <span class="p">{</span>
<span class="nl">_tag</span><span class="p">:</span> <span class="dl">"</span><span class="s2">FETCHING_FAILED</span><span class="dl">"</span><span class="p">;</span>
<span class="nl">error</span><span class="p">:</span> <span class="nb">Error</span><span class="p">;</span>
<span class="p">}</span>
<span class="kr">interface</span> <span class="nx">RefreshingData</span><span class="o"><</span><span class="nx">T</span><span class="o">></span> <span class="p">{</span>
<span class="na">_tag</span><span class="p">:</span> <span class="dl">"</span><span class="s2">REFRESHING_DATA</span><span class="dl">"</span><span class="p">;</span>
<span class="nl">data</span><span class="p">:</span> <span class="nx">T</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">type</span> <span class="nx">FetchData</span><span class="o"><</span><span class="nx">T</span><span class="o">></span> <span class="o">=</span>
<span class="o">|</span> <span class="nx">FetchingData</span>
<span class="o">|</span> <span class="nx">FetchedData</span><span class="o"><</span><span class="nx">T</span><span class="o">></span>
<span class="o">|</span> <span class="nx">RefreshingData</span><span class="o"><</span><span class="nx">T</span><span class="o">></span>
<span class="o">|</span> <span class="nx">FetchingFailed</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">fetchingData</span><span class="p">:</span> <span class="nx">FetchData</span><span class="o"><</span><span class="nx">never</span><span class="o">></span> <span class="o">=</span>
<span class="p">{</span> <span class="na">_tag</span><span class="p">:</span> <span class="dl">"</span><span class="s2">FETCHING_DATA </span><span class="dl">"</span><span class="p">};</span>
<span class="kd">const</span> <span class="nx">fetchedData</span> <span class="o">=</span> <span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">(</span><span class="nx">data</span><span class="p">:</span> <span class="nx">T</span><span class="p">):</span> <span class="nx">FetchData</span><span class="o"><</span><span class="nx">T</span><span class="o">></span> <span class="o">=></span> <span class="p">({</span>
<span class="na">_tag</span><span class="p">:</span> <span class="dl">"</span><span class="s2">FETCHED_DATA</span><span class="dl">"</span><span class="p">,</span>
<span class="nx">data</span>
<span class="p">});</span>
<span class="kd">const</span> <span class="nx">refreshingData</span> <span class="o">=</span> <span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">(</span><span class="nx">data</span><span class="p">:</span> <span class="nx">T</span><span class="p">):</span> <span class="nx">FetchData</span><span class="o"><</span><span class="nx">T</span><span class="o">></span> <span class="o">=></span> <span class="p">({</span>
<span class="na">_tag</span><span class="p">:</span> <span class="dl">"</span><span class="s2">REFRESHING_DATA</span><span class="dl">"</span><span class="p">,</span>
<span class="nx">data</span>
<span class="p">});</span>
<span class="kd">const</span> <span class="nx">fetchingFailed</span> <span class="o">=</span> <span class="p">(</span><span class="nx">error</span><span class="p">:</span> <span class="nb">Error</span><span class="p">):</span> <span class="nx">FetchData</span><span class="o"><</span><span class="nx">never</span><span class="o">></span> <span class="o">=></span> <span class="p">({</span>
<span class="na">_tag</span><span class="p">:</span> <span class="dl">"</span><span class="s2">FETCHING_FAILED</span><span class="dl">"</span><span class="p">,</span>
<span class="nx">error</span>
<span class="p">});</span>
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">FetchData<T></code> is a generic type that is either <code class="language-plaintext highlighter-rouge">FetchingData</code>, <code class="language-plaintext highlighter-rouge">FetchedData<T></code>, <code class="language-plaintext highlighter-rouge">RefreshingData<T></code> or <code class="language-plaintext highlighter-rouge">FetchingFailed</code>. It cannot be more than one of them at the same time. Furthermore, you cannot make assumptions about the data: the only thing the alternatives have in common is the <code class="language-plaintext highlighter-rouge">_tag</code> field, which should be used to <a href="https://www.typescriptlang.org/docs/handbook/advanced-types.html#discriminated-unions">discriminate between the alternatives</a>. You have to check that field’s value in order to be allowed to reach into the objects.</p>
<p>That means you can’t have <code class="language-plaintext highlighter-rouge">error</code> and <code class="language-plaintext highlighter-rouge">data</code> at the same time. Nor can you have <code class="language-plaintext highlighter-rouge">error</code> and <code class="language-plaintext highlighter-rouge">isLoading</code>. There’s no way to have an invalid state:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">renderData</span><span class="p">:</span> <span class="nx">IO</span><span class="o"><</span><span class="k">void</span><span class="o">></span> <span class="o">=</span> <span class="p">(</span><span class="nx">state</span><span class="p">:</span> <span class="nx">FetchedData</span><span class="o"><</span><span class="kr">string</span><span class="o">></span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">switch</span> <span class="p">(</span><span class="nx">state</span><span class="p">.</span><span class="nx">_tag</span><span class="p">)</span> <span class="p">{</span>
<span class="k">case</span> <span class="dl">"</span><span class="s2">FETCHING_DATA</span><span class="dl">"</span><span class="p">:</span>
<span class="k">return</span> <span class="nx">renderIsLoading</span><span class="p">();</span>
<span class="k">case</span> <span class="dl">"</span><span class="s2">FETCHED_DATA</span><span class="dl">"</span><span class="p">:</span>
<span class="k">return</span> <span class="nx">renderData</span><span class="p">(</span><span class="nx">state</span><span class="p">.</span><span class="nx">data</span><span class="p">);</span>
<span class="k">case</span> <span class="dl">"</span><span class="s2">FETCHING_FAILED</span><span class="dl">"</span><span class="p">:</span>
<span class="k">return</span> <span class="nx">renderError</span><span class="p">(</span><span class="nx">state</span><span class="p">.</span><span class="nx">error</span><span class="p">);</span>
<span class="k">case</span> <span class="dl">"</span><span class="s2">REFRESHING_DATA</span><span class="dl">"</span><span class="p">:</span>
<span class="k">return</span> <span class="nx">renderRefreshing</span><span class="p">(</span><span class="nx">state</span><span class="p">.</span><span class="nx">data</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kd">const</span> <span class="nx">state</span> <span class="o">=</span> <span class="nx">fetchedData</span><span class="p">(</span><span class="dl">"</span><span class="s2">oh data my data</span><span class="dl">"</span><span class="p">);</span>
<span class="nx">renderData</span><span class="p">(</span><span class="nx">state</span><span class="p">);</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">state</span><span class="p">.</span><span class="nx">data</span><span class="p">);</span>
<span class="c1">// Property 'data' does not exist on type 'FetchData<string>'.</span>
<span class="c1">// Property 'data' does not exist on type 'FetchingData'.</span>
</code></pre></div></div>
<p>It’s not uncommon to hear something to the tune of “that’s a lot of code”. I usually point out that many tests will not have to be written, and that it’s a lot clearer than nested if statements or large conditionals.</p>
<h2 id="fp-ts">fp-ts</h2>
<p><a href="https://gcanti.github.io/fp-ts/">fp-ts</a> gives you many of the tools you get in Haskell, PureScript or Scala, and a lot of convenience functions to lift your regular TypeScript to a transformation-friendly style. It encodes higher-kinded types using <a href="https://www.cl.cam.ac.uk/~jdy22/papers/lightweight-higher-kinded-polymorphism.pdf">Lightweight higher-kinded polymorphism</a>, since TypeScript doesn’t have that feature. You get used to specifying HKT instances by hand pretty quickly.</p>
<p>Due to TypeScript’s type inferencing limitations, a lot of your code will use <code class="language-plaintext highlighter-rouge">pipe</code> (it’s not unlike using <code class="language-plaintext highlighter-rouge">|></code> in Elm). This might make it confusing at times, and you’ll eventually develop strategies and sensibilities regarding when to extract helpers and break large computations.</p>
<p>Your solutions can be very expressive, and the types will tell you a lot. In the following example, we’ll take that list of animals from earlier, filter by their class and names, then fetch their Wikipedia pages concurrently and build a list of the results, failing the entire computation if an error occurs:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="p">{</span> <span class="nx">flow</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">fp-ts/lib/function</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">pipeable</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">fp-ts/lib/pipeable</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="o">*</span> <span class="k">as</span> <span class="nx">A</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">fp-ts/lib/Array</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="o">*</span> <span class="k">as</span> <span class="nx">O</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">fp-ts/lib/Option</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="o">*</span> <span class="k">as</span> <span class="nx">TE</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">fp-ts/lib/TaskEither</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">TaskEither</span> <span class="o">=</span> <span class="nx">TE</span><span class="p">.</span><span class="nx">TaskEither</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">reptilesWithGWikipediaArticles</span><span class="p">:</span> <span class="nx">TaskEither</span><span class="o"><</span><span class="nx">WikipediaArticle</span><span class="p">[]</span><span class="o">></span> <span class="o">=</span> <span class="nx">pipe</span><span class="p">(</span>
<span class="nx">animals</span><span class="p">,</span>
<span class="nx">A</span><span class="p">.</span><span class="nx">filterMap</span><span class="p">(</span>
<span class="nx">flow</span><span class="p">(</span>
<span class="nx">option</span><span class="p">.</span><span class="nx">some</span><span class="p">,</span>
<span class="nx">option</span><span class="p">.</span><span class="nx">filter</span><span class="p">(</span><span class="nx">a</span> <span class="o">=></span> <span class="nx">a</span><span class="p">.</span><span class="kd">class</span> <span class="o">===</span> <span class="dl">"</span><span class="s2">reptile</span><span class="dl">"</span> <span class="o">&&</span> <span class="nx">a</span><span class="p">.</span><span class="nx">name</span><span class="p">.</span><span class="nx">startsWith</span><span class="p">(</span><span class="dl">"</span><span class="s2">g</span><span class="dl">"</span><span class="p">)),</span>
<span class="nx">option</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">fetchWikipediaArticle</span><span class="p">)</span>
<span class="p">)</span>
<span class="p">),</span>
<span class="nx">A</span><span class="p">.</span><span class="nx">sequence</span><span class="p">(</span><span class="nx">TE</span><span class="p">.</span><span class="nx">taskEither</span><span class="p">)</span>
<span class="p">);</span>
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">TaskEither</code> defines an asynchronous computation that can fail. <code class="language-plaintext highlighter-rouge">filterMap</code> allows you to filter an array and change entries at the same time. <code class="language-plaintext highlighter-rouge">sequence</code> allows you to turn a list of asynchronous computations into an asynchronous computation with a list.</p>
<p>fp-ts forms a rich ecosystem of libraries that give you lenses, runtime encoding/decoding of types, parser combinators and other niceties you’ve probably heard about or used.</p>
<h2 id="putting-it-all-together-functional-typescript-in-the-workplace">Putting it all together: Functional TypeScript in the workplace</h2>
<p>We’ve been using all of the above (and very little more) at my day job for 10 months, building a robust HTTP API that’s serving millions of requests per day, integrating with dozens of services. It goes weeks between serving 500s, and using proper types to model computations that can fail forces the team to handle errors and introduce fallback strategies.</p>
<p>I consider it a great technical success. But this is only part of the story: getting there required my team to find their footing and get comfortable.</p>
<p>Since I was the one tasked with getting the service off the ground, I built a proof-of-concept and presented it to them. <em>When I had the buy-in</em>, I immediately became responsible for training and helping everyone in getting along with the codebase. If you find yourself in the same situation, be prepared to pair program, change pedagogy, and be patient. Remember it’s a very different way to do things. You should be able to show different solutions in different styles, as well as refrain from reviewing negatively code that could be more functional.</p>
<p>Would I be more satisfied working in Haskell? Perhaps. The fact is I wouldn’t be doing this style of programming professionally, in a conservative technical setting, were it not for node.js being acceptable and TypeScript being adopted by other squads. This pairing makes for a good Trojan horse, and it’s ergonomic enough that the experience ends up being quite pleasant. A lot more people end up being exposed to solving problems differently, to boot. At the end of the day, that’s the biggest win.</p>(edited for clarity in 2020-09-11T00:28:15Z)Decoding larger JSON objects in Elm 0.152015-08-17T22:31:00+00:002015-08-17T22:31:00+00:00http://troikatech.com/blog/2015/08/17/decoding-larger-json-objects-in-elm<p><a href="http://elm-lang.org/">Elm</a> is pretty cool. It’s a functional programming language with a <a href="https://www.youtube.com/watch?v=oYk8CKH7OhE">focus on usability</a>, strongly-typed but unceremonious, with nice type inferencing, good documentation and great stewardship from its creator, <a href="http://evan.czaplicki.us/">Evan Czaplicki</a>.</p>
<p>It’s so cool I’ve given an excited talk about it at work after only a couple of weeks of fiddling with it. And whenever I speak about tech, I try to add a demo or two to tie things together and make points clearer. That led to <a href="https://github.com/dodecaphonic/elm-forecast">elm-forecast</a>, a tiny app showing how to call APIs, decode JSON and display things on the screen.</p>
<p><img src="https://s3.amazonaws.com/troikatech/elm_json/elm-forecast.gif" alt="What elm-forecast looks like" /></p>
<h2 id="the-problem">The problem</h2>
<p><a href="https://developer.forecast.io/">Dark Sky’s JSON API</a> offers detailed weather information for most of the world. It has up-to-the minute data for some locations, and powers a lot of nice weather apps, like <a href="http://forecast.io">forecast.io</a> and <a href="https://play.google.com/store/apps/details?id=com.samruston.weather&hl=en">Weather Timeline</a>. My app was also going to be nice, so I picked it as my data source.</p>
<p>I started by wrapping the current forecast definition as a <a href="http://elm-lang.org/docs/records">record</a>:</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">type</span> <span class="n">alias</span> <span class="kt">Forecast</span> <span class="o">=</span> <span class="p">{</span> <span class="n">time</span> <span class="o">:</span> <span class="kt">Int</span>
<span class="p">,</span> <span class="n">summary</span> <span class="o">:</span> <span class="kt">String</span>
<span class="p">,</span> <span class="n">icon</span> <span class="o">:</span> <span class="kt">String</span>
<span class="p">,</span> <span class="n">precipIntensity</span> <span class="o">:</span> <span class="kt">Float</span>
<span class="p">,</span> <span class="n">precipProbability</span> <span class="o">:</span> <span class="kt">Float</span>
<span class="p">,</span> <span class="n">temperature</span> <span class="o">:</span> <span class="kt">Float</span>
<span class="p">,</span> <span class="n">windSpeed</span> <span class="o">:</span> <span class="kt">Float</span>
<span class="p">,</span> <span class="n">windBearing</span> <span class="o">:</span> <span class="kt">Float</span>
<span class="p">,</span> <span class="n">humidity</span> <span class="o">:</span> <span class="kt">Float</span>
<span class="p">,</span> <span class="n">visibility</span> <span class="o">:</span> <span class="kt">Float</span>
<span class="p">,</span> <span class="n">cloudCover</span> <span class="o">:</span> <span class="kt">Float</span>
<span class="p">,</span> <span class="n">pressure</span> <span class="o">:</span> <span class="kt">Float</span>
<span class="p">,</span> <span class="n">ozone</span> <span class="o">:</span> <span class="kt">Float</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Record types marry a lot of the feel of JavaScript objects with static types (the things after the colons).</p>
<p>If you’re familiar with dynamic languages, the next step will seem alien: instead of just calling something like <code class="language-plaintext highlighter-rouge">JSON.parse(obj)</code> and referencing its fields, we have to tell Elm how to make a typed <code class="language-plaintext highlighter-rouge">Forecast</code> out of the serialized data.</p>
<p>Let’s see what it looks like with a smaller object:</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">$</span> <span class="n">elm</span> <span class="n">repl</span>
<span class="kt">Elm</span> <span class="kt">REPL</span> <span class="mf">0.4</span><span class="o">.</span><span class="mi">2</span> <span class="p">(</span><span class="kt">Elm</span> <span class="kt">Platform</span> <span class="mf">0.15</span><span class="o">.</span><span class="mi">1</span><span class="p">)</span>
<span class="kt">See</span> <span class="n">usage</span> <span class="n">examples</span> <span class="n">at</span> <span class="o"><</span><span class="n">https</span><span class="o">://</span><span class="n">github</span><span class="o">.</span><span class="n">com</span><span class="o">/</span><span class="n">elm</span><span class="o">-</span><span class="n">lang</span><span class="o">/</span><span class="n">elm</span><span class="o">-</span><span class="n">repl</span><span class="o">></span>
<span class="kt">Type</span> <span class="o">:</span><span class="n">help</span> <span class="n">for</span> <span class="n">help</span><span class="p">,</span> <span class="o">:</span><span class="n">exit</span> <span class="n">to</span> <span class="n">exit</span>
<span class="o">></span> <span class="kr">import</span> <span class="nn">Json.Decode</span> <span class="k">as</span> <span class="n">Json</span> <span class="n">exposing</span> <span class="p">((</span><span class="o">:=</span><span class="p">))</span>
<span class="o">></span> <span class="kr">type</span> <span class="n">alias</span> <span class="kt">Point</span> <span class="o">=</span> <span class="p">{</span> <span class="n">x</span><span class="o">:</span> <span class="kt">Float</span><span class="p">,</span> <span class="n">y</span><span class="o">:</span> <span class="kt">Float</span> <span class="p">}</span>
<span class="o">></span> <span class="n">serialized</span> <span class="o">=</span> <span class="s">"{</span><span class="se">\"</span><span class="s">x</span><span class="se">\"</span><span class="s">: -43.123, </span><span class="se">\"</span><span class="s">y</span><span class="se">\"</span><span class="s">: -22.321}"</span>
<span class="s">"{</span><span class="se">\"</span><span class="s">x</span><span class="se">\"</span><span class="s">: -43.123, </span><span class="se">\"</span><span class="s">y</span><span class="se">\"</span><span class="s">: -22.321}"</span> <span class="o">:</span> <span class="kt">String</span>
<span class="o">></span> <span class="n">pointDecoder</span> <span class="o">=</span> <span class="kt">Json</span><span class="o">.</span><span class="n">object2</span> <span class="nf">\</span>
<span class="o">|</span> <span class="kt">Point</span> <span class="nf">\</span>
<span class="o">|</span> <span class="p">(</span><span class="s">"x"</span> <span class="o">:=</span> <span class="kt">Json</span><span class="o">.</span><span class="n">float</span><span class="p">)</span> <span class="nf">\</span>
<span class="o">|</span> <span class="p">(</span><span class="s">"y"</span> <span class="o">:=</span> <span class="kt">Json</span><span class="o">.</span><span class="n">float</span><span class="p">)</span>
<span class="o"><</span><span class="n">function</span><span class="o">></span> <span class="o">:</span> <span class="kt">Json</span><span class="o">.</span><span class="kt">Decode</span><span class="o">.</span><span class="kt">Decoder</span> <span class="kt">Repl</span><span class="o">.</span><span class="kt">Point</span>
<span class="o">></span> <span class="kt">Json</span><span class="o">.</span><span class="n">decodeString</span> <span class="n">pointDecoder</span> <span class="n">serialized</span>
<span class="kt">Ok</span> <span class="p">{</span> <span class="n">x</span> <span class="o">=</span> <span class="o">-</span><span class="mf">43.123</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="o">-</span><span class="mf">22.321</span> <span class="p">}</span> <span class="o">:</span> <span class="kt">Result</span><span class="o">.</span><span class="kt">Result</span> <span class="kt">String</span> <span class="kt">Repl</span><span class="o">.</span><span class="kt">Point</span>
</code></pre></div></div>
<p>The code above defines a type <code class="language-plaintext highlighter-rouge">Point</code> and a <code class="language-plaintext highlighter-rouge">Json.Decode.Decoder</code> <code class="language-plaintext highlighter-rouge">pointDecoder</code>, which takes care of deserializing an object with two fields (<code class="language-plaintext highlighter-rouge">object2</code>) and returning a <code class="language-plaintext highlighter-rouge">Point</code>. As you can see, no types have been declared, yet Elm has inferred every single one of them.</p>
<p><code class="language-plaintext highlighter-rouge">Json.Decode</code> has functions from <code class="language-plaintext highlighter-rouge">object1</code> to <code class="language-plaintext highlighter-rouge">object8</code>, capable of building objects with one up to eight fields. What to do with <code class="language-plaintext highlighter-rouge">Forecast</code>, that has <strong>13</strong>? <em>“Throw away five things, it’s just an example app you’re building to learn Elm”</em>, thought the lazy author. Luckily, thirst for knowledge (and a little guilt) averted that course, and I relied on what little functional programming I know to <em>almost</em> get there using <a href="http://package.elm-lang.org/packages/elm-lang/core/1.0.0/Json-Decode#andThen"><code class="language-plaintext highlighter-rouge">Json.Decoder.andThen</code></a>. Since <em>almost</em> is actually <em>not quite</em>, to Google I went. <a href="https://groups.google.com/forum/m/#!topic/elm-discuss/2LxEUVe0UBo">A thread with a recipe from mr. Czaplicki himself</a> offered the following solution:</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">import</span> <span class="nn">Json.Decode</span> <span class="k">as</span> <span class="n">Json</span>
<span class="n">apply</span> <span class="o">:</span> <span class="kt">Json</span><span class="o">.</span><span class="kt">Decoder</span> <span class="p">(</span><span class="n">a</span> <span class="o">-></span> <span class="n">b</span><span class="p">)</span> <span class="o">-></span> <span class="kt">Json</span><span class="o">.</span><span class="kt">Decoder</span> <span class="n">a</span> <span class="o">-></span> <span class="kt">Json</span><span class="o">.</span><span class="kt">Decoder</span> <span class="n">b</span>
<span class="n">apply</span> <span class="n">func</span> <span class="n">value</span> <span class="o">=</span>
<span class="kt">Json</span><span class="o">.</span><span class="n">object2</span> <span class="p">(</span><span class="o"><|</span><span class="p">)</span> <span class="n">func</span> <span class="n">value</span>
</code></pre></div></div>
<p>Let’s see it in action:</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">></span> <span class="n">newPointDecoder</span> <span class="o">=</span> <span class="kt">Json</span><span class="o">.</span><span class="n">map</span> <span class="kt">Point</span> <span class="p">(</span><span class="s">"x"</span> <span class="o">:=</span> <span class="kt">Json</span><span class="o">.</span><span class="n">float</span><span class="p">)</span> <span class="p">`</span><span class="n">apply</span><span class="p">`</span> <span class="p">(</span><span class="s">"y"</span> <span class="o">:=</span> <span class="kt">Json</span><span class="o">.</span><span class="n">float</span><span class="p">)</span>
<span class="o"><</span><span class="n">function</span><span class="o">></span> <span class="o">:</span> <span class="kt">Json</span><span class="o">.</span><span class="kt">Decode</span><span class="o">.</span><span class="kt">Decoder</span> <span class="kt">Repl</span><span class="o">.</span><span class="kt">Point</span>
<span class="o">></span> <span class="kt">Json</span><span class="o">.</span><span class="n">decodeString</span> <span class="n">newPointDecoder</span> <span class="n">serialized</span>
<span class="kt">Ok</span> <span class="p">{</span> <span class="n">x</span> <span class="o">=</span> <span class="o">-</span><span class="mf">43.123</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="o">-</span><span class="mf">22.321</span> <span class="p">}</span> <span class="o">:</span> <span class="kt">Result</span><span class="o">.</span><span class="kt">Result</span> <span class="kt">String</span> <span class="kt">Repl</span><span class="o">.</span><span class="kt">Point</span>
</code></pre></div></div>
<p>With <code class="language-plaintext highlighter-rouge">apply</code>, you can chain as many decoders as you like and build <code class="language-plaintext highlighter-rouge">objectN</code>. But how does it work?</p>
<h2 id="a-detour-to-the-world-of-partial-application">A detour to the world of Partial Application</h2>
<p>In Elm, like in Haskell, every function is <em>curried</em>. What it means, in practice, is that every function takes a single argument and returns a value, which can in turn be another function, taking a single argument, returning a value, and so forth. I’ll define a function <code class="language-plaintext highlighter-rouge">add</code> that (oh, how impressive) adds two numbers:</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">></span> <span class="n">add</span> <span class="n">x</span> <span class="n">y</span> <span class="o">=</span> <span class="n">x</span> <span class="o">+</span> <span class="n">y</span>
<span class="o"><</span><span class="n">function</span><span class="o">></span> <span class="o">:</span> <span class="n">number</span> <span class="o">-></span> <span class="n">number</span> <span class="o">-></span> <span class="n">number</span>
<span class="o">></span> <span class="n">add</span> <span class="mi">2</span> <span class="mi">3</span>
<span class="mi">5</span> <span class="o">:</span> <span class="n">number</span>
</code></pre></div></div>
<p>It looks like a function call with two arguments, like you see in most other languages. But look at the type signature the compiler inferred: <code class="language-plaintext highlighter-rouge">add : number -> number -> number</code>. What do the arrows represent? Well, they tell you exactly that the paragraph above tries to explain. Let’s see:</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">></span> <span class="n">add2</span> <span class="o">=</span> <span class="n">add</span> <span class="mi">2</span>
<span class="o"><</span><span class="n">function</span><span class="o">></span> <span class="o">:</span> <span class="n">number</span> <span class="o">-></span> <span class="n">number</span>
<span class="o">></span> <span class="n">add2</span> <span class="mi">3</span>
<span class="mi">5</span> <span class="o">:</span> <span class="n">number</span>
</code></pre></div></div>
<p>When defining <code class="language-plaintext highlighter-rouge">add2</code>, I’ve <em>partially</em> applied <code class="language-plaintext highlighter-rouge">add</code> with <code class="language-plaintext highlighter-rouge">2</code>, getting another function (now from <code class="language-plaintext highlighter-rouge">number -> number</code>). Calling that function will then result in a final number, the <code class="language-plaintext highlighter-rouge">5</code> literal that amazes people all over the world. This very characteristic helps you build <code class="language-plaintext highlighter-rouge">apply</code>.</p>
<p>In the example a few paragraphs above, <code class="language-plaintext highlighter-rouge">Point</code> is a function with the signature <code class="language-plaintext highlighter-rouge">Float -> Float -> Point</code>. That means that if I try to use it with a single decoder, it will move closer to getting an actual <code class="language-plaintext highlighter-rouge">Point</code>, but not get there yet:</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">></span> <span class="kt">Json</span><span class="o">.</span><span class="n">map</span> <span class="kt">Point</span> <span class="p">(</span><span class="s">"x"</span> <span class="o">:=</span> <span class="kt">Json</span><span class="o">.</span><span class="n">float</span><span class="p">)</span>
<span class="o"><</span><span class="n">function</span><span class="o">></span> <span class="o">:</span> <span class="kt">Json</span><span class="o">.</span><span class="kt">Decode</span><span class="o">.</span><span class="kt">Decoder</span> <span class="p">(</span><span class="kt">Float</span> <span class="o">-></span> <span class="kt">Repl</span><span class="o">.</span><span class="kt">Point</span><span class="p">)</span>
</code></pre></div></div>
<p>Looking at the type signature, it’s a structure that decodes a <code class="language-plaintext highlighter-rouge">Float</code> and returns another structure that can decode a function <code class="language-plaintext highlighter-rouge">Float -> Point</code>. If I tried to do the same thing with a type constructor that took more arguments, say <code class="language-plaintext highlighter-rouge">Float -> String -> Bool -> String -> Value</code>, the first step would yield a Decoder with type <code class="language-plaintext highlighter-rouge">(String -> Bool -> String -> Value)</code> — solved for the first parameter, still waiting for a resolution for the next three.</p>
<p>What <code class="language-plaintext highlighter-rouge">apply</code> does then is leverage the fact that you can progressively get to your final value by applying function by function, taking care of spitting out every every step as a <code class="language-plaintext highlighter-rouge">Json.Decoder</code>. There’s a name for this pattern of having a function in a box and applying it to values in other boxes: it’s an <a href="https://wiki.haskell.org/Typeclassopedia#Applicative">Applicative functor</a>. Now, if you’ve read a bit about the language, you know that Elm shies away from the burden of a Math-y, Haskell-y lexicon. The great thing is that by hiding the words but showing things in practice, it ends up fostering an intuition in programmers for how the concepts can be <em>useful</em>.</p>
<p>Let’s go back to <code class="language-plaintext highlighter-rouge">Json.Decode.object2</code>. It expects <code class="language-plaintext highlighter-rouge">(a -> b -> c) -> Decoder a -> Decoder b -> Decoder c</code> — a function from type <code class="language-plaintext highlighter-rouge">a</code> to <code class="language-plaintext highlighter-rouge">b</code> to <code class="language-plaintext highlighter-rouge">c</code> and <code class="language-plaintext highlighter-rouge">Decoder</code>s for <code class="language-plaintext highlighter-rouge">a</code> and <code class="language-plaintext highlighter-rouge">b</code>, yielding a <code class="language-plaintext highlighter-rouge">Decoder c</code>. In our definition <code class="language-plaintext highlighter-rouge">pointDecoder</code> in the beginning of this post, we matched that to a tee, as <code class="language-plaintext highlighter-rouge">Point</code> can be seen as a function taking two <code class="language-plaintext highlighter-rouge">Floats</code> (<code class="language-plaintext highlighter-rouge">a</code> and <code class="language-plaintext highlighter-rouge">b</code>) and returning a <code class="language-plaintext highlighter-rouge">Point</code> record (<code class="language-plaintext highlighter-rouge">c</code>). But <code class="language-plaintext highlighter-rouge">a</code>, <code class="language-plaintext highlighter-rouge">b</code> or <code class="language-plaintext highlighter-rouge">c</code> can also be a function! In fact, that’s exactly what we’ve seen above with <code class="language-plaintext highlighter-rouge">Json.Decode.Decoder (Float -> Repl.Point)</code>. Thus, when we say:</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">></span> <span class="kt">Json</span><span class="o">.</span><span class="n">object2</span> <span class="p">(</span><span class="o"><|</span><span class="p">)</span> <span class="n">func</span> <span class="n">value</span>
</code></pre></div></div>
<p>and replace <code class="language-plaintext highlighter-rouge">func</code> with <code class="language-plaintext highlighter-rouge">Json.Decoder.Decode (Float -> Point)</code> and <code class="language-plaintext highlighter-rouge">value</code> with <code class="language-plaintext highlighter-rouge">("y" := Json.float)</code>, we’ll end up with a <code class="language-plaintext highlighter-rouge">Decoder</code> built of applying what’s coming out of <code class="language-plaintext highlighter-rouge">value</code> to <code class="language-plaintext highlighter-rouge">Float -> Point</code>, arriving at <code class="language-plaintext highlighter-rouge">Decoder Point</code>. If we manually try to build the same chain, it looks like this:</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">></span> <span class="kr">import</span> <span class="nn">Json.Decode</span> <span class="k">as</span> <span class="n">Json</span> <span class="n">exposing</span> <span class="p">((</span><span class="o">:=</span><span class="p">),</span> <span class="n">andThen</span><span class="p">)</span>
<span class="o">></span> <span class="kr">type</span> <span class="n">alias</span> <span class="kt">Point</span> <span class="o">=</span> <span class="p">{</span> <span class="n">x</span><span class="o">:</span> <span class="kt">Float</span><span class="p">,</span> <span class="n">y</span><span class="o">:</span> <span class="kt">Float</span> <span class="p">}</span>
<span class="o">></span> <span class="n">partialDecoder</span> <span class="o">=</span> <span class="kt">Json</span><span class="o">.</span><span class="n">succeed</span><span class="p">(</span><span class="kt">Point</span><span class="p">)</span> <span class="p">`</span><span class="n">andThen</span><span class="p">`</span> <span class="nf">\</span>
<span class="p">(</span><span class="nf">\</span><span class="n">f</span> <span class="o">-></span> <span class="p">(</span><span class="s">"x"</span> <span class="o">:=</span> <span class="kt">Json</span><span class="o">.</span><span class="n">float</span><span class="p">)</span> <span class="p">`</span><span class="n">andThen</span><span class="p">`</span> <span class="nf">\</span>
<span class="p">(</span><span class="nf">\</span><span class="n">x</span> <span class="o">-></span> <span class="kt">Json</span><span class="o">.</span><span class="n">succeed</span> <span class="o"><|</span> <span class="n">f</span> <span class="n">x</span><span class="p">))</span>
<span class="o"><</span><span class="n">function</span><span class="o">></span> <span class="o">:</span> <span class="kt">Json</span><span class="o">.</span><span class="kt">Decode</span><span class="o">.</span><span class="kt">Decoder</span> <span class="p">(</span><span class="kt">Float</span> <span class="o">-></span> <span class="kt">Repl</span><span class="o">.</span><span class="kt">Point</span><span class="p">)</span>
<span class="o">></span> <span class="n">decoderPoint</span> <span class="o">=</span> <span class="n">partialDecoder</span> <span class="p">`</span><span class="n">andThen</span><span class="p">`</span> <span class="nf">\</span>
<span class="p">(</span><span class="nf">\</span><span class="n">f</span> <span class="o">-></span> <span class="p">(</span><span class="s">"y"</span> <span class="o">:=</span> <span class="kt">Json</span><span class="o">.</span><span class="n">float</span><span class="p">)</span> <span class="p">`</span><span class="n">andThen</span><span class="p">`</span> <span class="nf">\</span>
<span class="p">(</span><span class="nf">\</span><span class="n">y</span> <span class="o">-></span> <span class="kt">Json</span><span class="o">.</span><span class="n">succeed</span> <span class="o"><|</span> <span class="n">f</span> <span class="n">y</span><span class="p">))</span>
<span class="o"><</span><span class="n">function</span><span class="o">></span> <span class="o">:</span> <span class="kt">Json</span><span class="o">.</span><span class="kt">Decode</span><span class="o">.</span><span class="kt">Decoder</span> <span class="kt">Repl</span><span class="o">.</span><span class="kt">Point</span>
</code></pre></div></div>
<p>Cool, right? Now that you and I understand the technique, we can go back to the gif above and marvel at how poor my CSS skills are.</p>
<h2 id="no-magic">No magic</h2>
<p>What I find the most refreshing as I dive into functional programming is that there’s (usually) no magic. If you start peeling the layers, there’s just functions brought together to perform amazing things. <code class="language-plaintext highlighter-rouge">apply</code> here is exactly that: the power of a few functions allowing you to convert arbitrarily large structures into a nice type Elm can understand. In a world of “factory this” “IoC container that”, you can’t help but smile. And it REALLY REALLY REALLY improves your programming everywhere: I’m a fan of saying my Ruby is much better and more maintainable after I decided to learn the functional ways because it’s true. Hopefully you can find the same joy.</p>Elm is pretty cool. It’s a functional programming language with a focus on usability, strongly-typed but unceremonious, with nice type inferencing, good documentation and great stewardship from its creator, Evan Czaplicki.Ruby is a friend2015-04-28T22:45:00+00:002015-04-28T22:45:00+00:00http://troikatech.com/blog/2015/04/28/ruby-is-a-friend<p>As time goes by, Ruby moves closer and closer to the “boring tech” bin: it’s tried, true and trite (at least by <a href="http://news.ycombinator.com">Hacker News</a> standards). And to be completely honest, I’ve often been taken by that same sentiment. The awareness of the privilege to be working with something that remains foreign to most of the Brazilian market has been replaced by a feeling of “not cool enough”, an anxiety for something as wonderful to happen again.</p>
<p>Analyzing things more carefully, however, I’ve realized how much it has allowed me to change as a coder. In Ruby, it’s very easy to go from “it’s like this in language <em>x</em>” to “it’s like this in Ruby, too.” The <a href="http://en.wikipedia.org/wiki/Moli%C3%A8re">“Belle marquise”</a> quality of expression it allows is a source of many joys, and can be quite invigorating as the relationship between it and the programmer develops.</p>
<p>We often feel pressured, in our field, to jump from thing to thing, from shiny to shiny, from silver bullet to silver bullet. “The best tool for the job cannot possibly be the tool you had five years ago” — chants the crowd as they try a new JavaScript build system — “it just isn’t right.” Reflecting on the role Ruby has had in my life, though, shines light on an aspect we rarely explore: a programming language is a friend. It’s not perfect, it can annoy you, but it’s there, and by merely being there and helping you think it makes you better.</p>
<p>Ruby is a <em>great</em> friend. We’ve been together for almost ten years. I can only hope I’ve been making it better too.</p>As time goes by, Ruby moves closer and closer to the “boring tech” bin: it’s tried, true and trite (at least by Hacker News standards). And to be completely honest, I’ve often been taken by that same sentiment. The awareness of the privilege to be working with something that remains foreign to most of the Brazilian market has been replaced by a feeling of “not cool enough”, an anxiety for something as wonderful to happen again.Maybe Haskell2015-04-02T08:06:00+00:002015-04-02T08:06:00+00:00http://troikatech.com/blog/2015/04/02/maybe-haskell<p>The programming world is one of trends and fashions. One week you’re on the top of the world for using that NoSQL database, and then you’re very wrong the next; one day it’s all about Rails, the next it’s node.js, now it’s Go. Using <a href="http://news.ycombinator.com">Hacker News</a> as a compass seemingly means discarding everything you’re doing now to follow the next big thing.</p>
<p>Like fashion, though, sometimes one of those new things is actually well-rounded, makes a mark and becomes permanent. Also like fashion, the new thing might be an old thing that people are rediscovering or just now ready to adopt. Judging by what’s on the specialized news, <a href="http://en.wikipedia.org/wiki/Functional_programming">Functional Programming</a> is the old-new rage that’s changing the world and is here to stay.</p>
<p>It’s no wonder: more enlightened programmers and language designers have sprinkled some of the joys of that paradigm upon our OO tools, making us giggle with happiness when chaining <code class="language-plaintext highlighter-rouge">map</code>s and <code class="language-plaintext highlighter-rouge">inject</code>s and taking blocks to change a method’s behavior, or using anonymous and higher-order functions in tired and uncool languages of yesteryear, feeling more productive all the way. It’s so transformative to think in pipelines and in functional composition that we end up wanting to know how to learn more and feel <em>even better</em>. Functional Programming called, and you answered.</p>
<p>But lo!, what is a catamorphism? What the hell is a Category, and why does it need a theory? Why did someone put a Monad in my burrito? Is Functor just a funny word Erik Meijer says?</p>
<p>Let’s face it: it can be daunting. None of the usual landmarks of what we call <em>programming</em> are there to guide you through learning, and it’s easy to feel inadequate and, dare I say it, intellectually inferior. Fear not: <a href="https://twitter.com/patbrisbin">Pat Brisbin</a> knows this, and is here to help.</p>
<h2 id="the-book">The Book</h2>
<p><a href="http://maybe-haskell.com">“Maybe Haskell”</a>, written by the aforementioned mr. Brisbin, is a book of the short and sweet kind. It quickly acknowledges that it probably will not be the definitive guide on any of the subjects it talks about, and moves right on to the material.</p>
<p>From the gates, the author explains referential transparency and uses equational reasoning to show you how a name for an expression (let’s say <code class="language-plaintext highlighter-rouge">add(x, y)</code>) can be replaced safely by the expression itself (<code class="language-plaintext highlighter-rouge">x + y</code>). This will become a tool later on to clarify that what seems so elaborate is actually pretty straightforward. It’s very effective, because it unfolds everything that looks so terse and codified into its components, and those components into their components, working as both a calming device (“see how simple it is? It’s just about context”) and an illustration of the power of function composition.</p>
<p>It then gets to its main thread: what is the <code class="language-plaintext highlighter-rouge">Maybe</code> type and how is it built? What does it mean to adopt <code class="language-plaintext highlighter-rouge">Maybe</code> in a code base, and how do you deal with it without having every function in your system taking and returning other <code class="language-plaintext highlighter-rouge">Maybe</code>s? Even if you’ve heard of or applied <code class="language-plaintext highlighter-rouge">Maybe</code>, it might give you ideas and reveal unknown subtleties — especially if all you’ve learned about it has been self-directed.</p>
<p>From that on you’ll hit three head-scratchers in sequence: Functors, Applicatives and Monads. It begins with showing you ways of not infecting your code with <code class="language-plaintext highlighter-rouge">Maybe</code> everywhere and ends with calling functions that take multiple <code class="language-plaintext highlighter-rouge">Maybe</code>s, dealing with the possibility of one or more of them not being there. The path is of full of little joys and insights to savor, and you’ll get what a Monad <em>does</em> by the end of it (even if the answer to what it <em>is</em> goes through endofunctors and other details).</p>
<p>What I greatly enjoyed was the “Other Types” section. It’s brief, but tackles how you can use the same building blocks to improve designs and make errors and side-effects more explicit. While I knew most of the benefits and the material, I thought about the complete novice and how that section could spark new ideas. I didn’t “ooh” and “aah” because it was new to me: I did because it will hook a lot of casually interested people who perhaps got the book because it came from someone in the Ruby world and aren’t very invested in the ideas of FP yet. It will definitely make <em>Ruby</em>, if nothing else, better.</p>
<p>In the end, even if “Maybe Haskell” just explains enough of what the language can do to support the examples, the quiet imponence and lack of pretense of the language become very evident. As the text progresses, you’ll see the ivory tower where FP wizards live for what it really is: a building that begins on the same ground you and I step on, made out of very solid and simple materials. Luckily we have Pat gently guiding us to that conclusion.</p>The programming world is one of trends and fashions. One week you’re on the top of the world for using that NoSQL database, and then you’re very wrong the next; one day it’s all about Rails, the next it’s node.js, now it’s Go. Using Hacker News as a compass seemingly means discarding everything you’re doing now to follow the next big thing.ENSIME and Emacs as a Scala IDE2014-11-26T10:38:00+00:002014-11-26T10:38:00+00:00http://troikatech.com/blog/2014/11/26/ensime-and-emacs-as-a-scala-ide<p><em>“Maybe Emacs is not enough.”</em></p>
<p>That popped up in my mind, and it scared me. I knew Scala was a different beast; I knew there was probably a lot I was missing out on by using my tried-and-true workflows; I knew that IntelliJ was supposed to be amazing. Still, thinking Emacs-the-almighty was not enough frightened me.</p>
<p>When I started on this slow path towards learning FP, I had been using dynamic languages almost exclusively for almost 14 years, with a short stop in C++-land for a couple of them. I was used to a world of mostly ok tools centered on a REPL, and it was fine — programming is more thinking than typing and clicking, that whole <em>spiel</em>. But I had never really done anything in a good type system, and, frankly, it was time I knew how the rest of the world leveraged their tools in order to work more comfortably and effectively.</p>
<p>With that in mind, I evaluated the Typesafe IDE and IntelliJ IDEA 12 and 13, finding a lot of good in both tools (and a few problems, some discussed in my post about the <a href="/blog/2014/01/12/reactive">Reactive Programming course</a>). Still, after a few good days with each option, I was tempted to just go back to Emacs and rely on my memory (and <a href="http://kapeli.com/dash">Dash</a>) for the API signatures, do all my code refactorings by hand and use the <code class="language-plaintext highlighter-rouge">sbt console</code> for quick explorations.</p>
<p>Then I found out I could have the cake and eat it too.</p>
<h2 id="enter-ensime">Enter ENSIME</h2>
<p>ENSIME (<strong>ENhanced Scala Interaction Mode for Emacs</strong>) is a project that gives Emacs IDE-like capabilities. It performs type and error-checking as you write code, provides symbol inspection, facilities for browsing your codebase and performing automated refactorings. It accomplishes all that using the <a href="http://scala-ide.org/docs/dev/architecture/presentation-compiler.html">Scala Presentation Compiler</a>, a lightweight version of the infrastructure that goes only as far as needed to resolve types, find errors and do semantic highlighting.</p>
<p>Setting it up is super simple. Using MELPA, install the <code class="language-plaintext highlighter-rouge">ensime</code> package. Then add the following to your Emacs config:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(require 'ensime)
(add-hook 'scala-mode-hook 'ensime-scala-mode-hook)
</code></pre></div></div>
<p>Then add the plugin to your global <code class="language-plaintext highlighter-rouge">sbt</code> config (e.g. <code class="language-plaintext highlighter-rouge">~/.sbt/0.13/plugins/plugins.sbt</code>):</p>
<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">resolvers</span> <span class="o">+=</span> <span class="nv">Resolver</span><span class="o">.</span><span class="py">sonatypeRepo</span><span class="o">(</span><span class="s">"snapshots"</span><span class="o">)</span>
<span class="nf">addSbtPlugin</span><span class="o">(</span><span class="s">"org.ensime"</span> <span class="o">%</span> <span class="s">"ensime-sbt"</span> <span class="o">%</span> <span class="s">"0.1.5-SNAPSHOT"</span><span class="o">)</span>
</code></pre></div></div>
<p>And then, in your project directory, run <code class="language-plaintext highlighter-rouge">sbt gen-ensime</code> (requires sbt >= 0.13.5). It will resolve the dependencies, install the ENSIME plugin and leave everything ready to go.</p>
<p>Now, when you open a buffer, you’re gonna see the following in your mode line:</p>
<p><img src="https://dl.dropboxusercontent.com/s/zss0kz5lr8hvhmr/2014-11-27%20at%2010.22.png" title="ENSIME Disconnected" /></p>
<p>Use <code class="language-plaintext highlighter-rouge">M-x ensime</code> to start a connection. It might take a few seconds for it to do what it must to analyze your project, but you’ll eventually see the mode line change to show it’s ready to work.</p>
<h2 id="code-completion">Code completion</h2>
<p>One of the cool things ENSIME provides is real code completion, based on the type you’re dealing with. Instead of the usual <code class="language-plaintext highlighter-rouge">M-/</code> cycling, you can explore an API by looking at the method signatures and documentation. Here’s the thing in action:</p>
<p><img src="https://s3.amazonaws.com/troikatech/ensime_as_ide/completion.gif" title="Completing" /></p>
<h2 id="type-inspection">Type inspection</h2>
<p>Sometimes Scala’s type inference engine gets confused, giving you something too broad or too narrow for your needs; other times, you just want to know the type of a <code class="language-plaintext highlighter-rouge">val</code>. Worry not: ENSIME can tell you what has been inferenced just by putting the cursor over the token you want and pressing <code class="language-plaintext highlighter-rouge">C-c C-v i</code> (works a bit like <code class="language-plaintext highlighter-rouge">:t</code> in <code class="language-plaintext highlighter-rouge">ghci</code>).</p>
<p><img src="https://s3.amazonaws.com/troikatech/ensime_as_ide/type_at_point.gif" title="Inspecting types" /></p>
<p>You can also show uses of a symbol by pressing <code class="language-plaintext highlighter-rouge">C-c C-v r</code>.</p>
<h2 id="automated-refactorings">Automated Refactorings</h2>
<p>ENSIME offers six simple, but extremely useful automated refactorings:</p>
<ul>
<li>Inline Local</li>
<li>Extract Local</li>
<li>Extract Method</li>
<li>Rename</li>
<li>Organize Imports</li>
<li>Import Type at Point</li>
</ul>
<p><img src="https://s3.amazonaws.com/troikatech/ensime_as_ide/refactoring.gif" title="Refactoring" /></p>
<p>Of all of these, <em>Import Type at Point</em> is the only one I’d consider flaky. It resolves the type perfectly, but inserts the <code class="language-plaintext highlighter-rouge">import</code> statement inline. I don’t know if that’s configurable. Otherwise, it works as many other automated tools: finds each change, shows you the substitution, asks you to ok it.</p>
<h2 id="navigation">Navigation</h2>
<p>You can use <code class="language-plaintext highlighter-rouge">M-.</code> and <code class="language-plaintext highlighter-rouge">M-*</code>, normally associated with finding tags, to move inside your project.</p>
<p><img src="https://s3.amazonaws.com/troikatech/ensime_as_ide/navigation.gif" title="Navigation" /></p>
<p>You can also jump from implementation to test, and vice versa.</p>
<h2 id="scala-and-sbt-integration"><code class="language-plaintext highlighter-rouge">scala</code> and <code class="language-plaintext highlighter-rouge">sbt</code> integration</h2>
<p>If you press <code class="language-plaintext highlighter-rouge">C-c C-v s</code>, an sbt console will be launched. A lot of my usual Ruby workflow of running specs from keybinds and jumping quickly to the REPL can be reproduced with this feature.</p>
<p>For instance, when you want to run all tests, you press <code class="language-plaintext highlighter-rouge">C-c C-b T</code>. When you wish only to invoke <code class="language-plaintext highlighter-rouge">testQuick</code>, you use <code class="language-plaintext highlighter-rouge">C-c C-b t</code>.</p>
<p>There’s keybinds for changing a region or a buffer, too — useful both for playing with code and exercising your Emacs gymnastics.</p>
<h2 id="finally">Finally</h2>
<p>ENSIME has been fun to work with. It allows me to focus on code and work comfortably with my (admittedly small) projects. It’s a great showcase of Emacs capabilities, and has led a couple of hardcore vim-using friends to show admiration.</p>
<p>If you’re doing Scala and don’t want to commit to an IDE, but wish to have more of a modern environment, please try ENSIME. I even hear there’s vim and jEdit clients.</p>“Maybe Emacs is not enough.”Functional Programming in Ruby2014-07-07T21:29:00+00:002014-07-07T21:29:00+00:00http://troikatech.com/blog/2014/07/07/functional-programming-in-ruby<p>On June 21th, 2014, I gave a talk about Functional Programming in Ruby in one of <a href="http://rubyonrio.org">RubyOnRio’s</a> monthly meetings. I decided to do a short overview of some concepts and techniques in the FP world and then go over <a href="https://twitter.com/garybernhardt">Gary Bernhardt’s</a> “<a href="https://www.destroyallsoftware.com/screencasts/catalog/functional-core-imperative-shell">Functional Core, Imperative Shell</a>” — after all, it would be a hard sell if I couldn’t show a way said techniques make your everyday coding better.</p>
<p>It didn’t get recorded this time, but I thought the slides could be interesting. Here they are.</p>
<script async="" class="speakerdeck-embed" data-id="77fedf60ddbf0131b761266a7d836638" data-ratio="1.34031413612565" src="https://speakerdeck.com/assets/embed.js"></script>On June 21th, 2014, I gave a talk about Functional Programming in Ruby in one of RubyOnRio’s monthly meetings. I decided to do a short overview of some concepts and techniques in the FP world and then go over Gary Bernhardt’s “Functional Core, Imperative Shell” — after all, it would be a hard sell if I couldn’t show a way said techniques make your everyday coding better.Property-based testing in Ruby2014-04-02T10:32:00+00:002014-04-02T10:32:00+00:00http://troikatech.com/blog/2014/04/02/property-based-testing-in-ruby<p>For the past year or so I have slowly been dipping my feet into the vast functional programming seas. From taking the awesome <a href="http://coursera.org">Coursera</a> <a href="https://www.coursera.org/course/progfun">offerings</a> <a href="https://www.coursera.org/course/reactive">from Typesafe</a> to slowly working through Rúnar Bjarnason’s and Paul Chiusano’s <em><a href="http://www.manning.com/bjarnason/">Functional Programming in Scala</a></em>, my mind has been expanding proportionally to the time I dedicate to learning its ways. It has been incredibly rewarding and humbling.</p>
<p>One such reward has been coming into direct touch with property-based testing. This technique, first developed by <a href="http://en.wikipedia.org/wiki/QuickCheck">QuickCheck</a> in Haskell-land, spins automated testing on its head: instead of codifying what is proper behavior by asserting that the outputs for given inputs match what is expected, the tester establishes logical properties about what should happen and lets the tool generate loads of inputs to check if they hold. If something goes wrong, the tool will then try to find the smallest test input that breaks the property (<em>falsifies</em> it), a process called <em>shrinking</em>; if it can’t find anything, you can sigh with relief and think about what to scrutinize next.</p>
<p>Having a QuickCheck-like tool at your disposal can be incredibly powerful. The more complex the software or the algorithm, the greater the likelihood of your carefully curated unit and integration tests having blind spots. <a href="http://basho.com">Basho</a>, for instance, <a href="http://basho.com/quickchecking-poolboy-for-fun-and-profit/">have written about the stark realization that their worker pool library was full of subtle bugs by using QuickCheck for Erlang</a>, and you can find <a href="http://www.quviq.com/documents/erlang001-arts.pdf">other</a> <a href="http://www.autosar.org/download/conferencedocs11/12_AUTOSAR_ModelBased_Quviq.pdf">instances</a> of how the technique helped make better software.</p>
<p>I don’t know about you, but when I come in contact with stuff like that I immediately think of how improved parts of my day job would be if I just could apply it. Considering that my daily duties are conducted in Ruby, I felt it was time I explored the subject in that realm.</p>
<h2 id="a-contrived-setup-that-hopefully-shows-how-it-can-work-out">A contrived setup that hopefully shows how it can work out</h2>
<p>Let’s say we’ve decided to implement our own linked list class in Ruby. We would probably start our implementation with something like this:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">require</span> <span class="s2">"singleton"</span>
<span class="k">class</span> <span class="nc">Nil</span>
<span class="kp">include</span> <span class="no">Singleton</span>
<span class="k">def</span> <span class="nf">empty?</span><span class="p">;</span> <span class="kp">true</span><span class="p">;</span> <span class="k">end</span>
<span class="k">def</span> <span class="nf">to_s</span>
<span class="s2">"Nil"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">Cons</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">head</span><span class="p">,</span> <span class="n">tail</span> <span class="o">=</span> <span class="no">Nil</span><span class="p">.</span><span class="nf">instance</span><span class="p">)</span>
<span class="vi">@head</span> <span class="o">=</span> <span class="n">head</span>
<span class="vi">@tail</span> <span class="o">=</span> <span class="n">tail</span>
<span class="k">end</span>
<span class="nb">attr_reader</span> <span class="ss">:head</span><span class="p">,</span> <span class="ss">:tail</span>
<span class="k">def</span> <span class="nf">empty?</span><span class="p">;</span> <span class="kp">false</span><span class="p">;</span> <span class="k">end</span>
<span class="k">def</span> <span class="nf">to_s</span>
<span class="s2">"(</span><span class="si">#{</span><span class="n">head</span><span class="si">}</span><span class="s2"> . </span><span class="si">#{</span><span class="n">tail</span><span class="p">.</span><span class="nf">to_s</span><span class="si">}</span><span class="s2">)"</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Using that <em>very</em> convenient API, we can build lists:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">>></span> <span class="n">l</span> <span class="o">=</span> <span class="no">Cons</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="no">Cons</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="no">Cons</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="no">Nil</span><span class="p">.</span><span class="nf">instance</span><span class="p">)))</span>
<span class="o">>></span> <span class="n">l</span><span class="p">.</span><span class="nf">to_s</span> <span class="c1"># => "(1 . (2 . (3 . Nil)))"</span>
</code></pre></div></div>
<p>We know that, in a linked list, adding to the head is O(1), while appending to the end is O(n). So we build algorithms that respect its efficiency guarantees. However, when we, say, map this list into another list, it results in the following situation:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">do_something_amazing</span><span class="p">(</span><span class="n">list</span><span class="p">,</span> <span class="n">acc</span> <span class="o">=</span> <span class="no">Nil</span><span class="p">.</span><span class="nf">instance</span><span class="p">)</span>
<span class="n">super_value</span> <span class="o">=</span> <span class="n">list</span><span class="p">.</span><span class="nf">head</span> <span class="o">*</span> <span class="mi">1337</span>
<span class="k">if</span> <span class="n">list</span><span class="p">.</span><span class="nf">tail</span><span class="p">.</span><span class="nf">empty?</span>
<span class="n">acc</span>
<span class="k">else</span>
<span class="n">do_something_amazing</span><span class="p">(</span><span class="n">list</span><span class="p">.</span><span class="nf">tail</span><span class="p">,</span> <span class="no">List</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">super_value</span><span class="p">,</span> <span class="n">acc</span><span class="p">))</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="o">>></span> <span class="n">do_something</span><span class="p">(</span><span class="n">l</span><span class="p">).</span><span class="nf">to_s</span> <span class="c1"># => "(4011 . (2674 . (1337 . Nil)))"</span>
</code></pre></div></div>
<p>Processing things from head to tail means the list ends up reversed. It’s common, then, to reverse it back when we’re done processing, to preserve the order an external user would expect. Let’s add a <code>reverse</code> method to a <code>List</code> helper module:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="nn">List</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">reverse</span><span class="p">(</span><span class="n">list</span><span class="p">,</span> <span class="n">acc</span> <span class="o">=</span> <span class="no">Nil</span><span class="p">.</span><span class="nf">instance</span><span class="p">)</span>
<span class="k">if</span> <span class="n">list</span><span class="p">.</span><span class="nf">empty?</span>
<span class="n">acc</span>
<span class="k">else</span>
<span class="n">reverse</span><span class="p">(</span><span class="n">list</span><span class="p">.</span><span class="nf">tail</span><span class="p">,</span> <span class="no">Cons</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">list</span><span class="p">.</span><span class="nf">head</span><span class="p">,</span> <span class="n">acc</span><span class="p">))</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>So when we try to reverse what was created in <code>do_something_amazing</code>, we get what we need:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">List</span><span class="p">.</span><span class="nf">reverse</span><span class="p">(</span><span class="n">do_something_amazing</span><span class="p">(</span><span class="n">l</span><span class="p">)).</span><span class="nf">to_s</span> <span class="c1"># => "(1337 . (2674 . (4011 . Nil)))"</span>
</code></pre></div></div>
<p>Awesome. I think this is enough for us to start exploring properties. If you’re getting bored, take a sip of coffee and come back when you’re ready. There’s a few cool tricks below the fold.</p>
<h2 id="testing-the-old-way">Testing the old way</h2>
<p>Being the good developers we are, we are covering that code with tests:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">ListTest</span> <span class="o"><</span> <span class="no">MiniTest</span><span class="o">::</span><span class="no">Test</span>
<span class="k">def</span> <span class="nf">test_reversing_lists</span>
<span class="n">assert_equal</span> <span class="s2">"(3 . (2 . (1 . Nil)))"</span><span class="p">,</span>
<span class="no">List</span><span class="p">.</span><span class="nf">reverse</span><span class="p">(</span><span class="no">Cons</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="no">Cons</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="no">Cons</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="mi">3</span><span class="p">)))).</span><span class="nf">to_s</span>
<span class="n">assert_equal</span> <span class="s2">"(9 . (400 . (321 . (1 . (10 . Nil)))))"</span><span class="p">,</span>
<span class="no">List</span><span class="p">.</span><span class="nf">reverse</span><span class="p">(</span><span class="no">Cons</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="no">Cons</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="no">Cons</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="mi">321</span><span class="p">,</span> <span class="no">Cons</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="mi">400</span><span class="p">,</span> <span class="no">Cons</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="mi">9</span><span class="p">)))))).</span><span class="nf">to_s</span>
<span class="n">assert_equal</span> <span class="s2">"Nil"</span><span class="p">,</span> <span class="no">List</span><span class="p">.</span><span class="nf">reverse</span><span class="p">(</span><span class="no">Nil</span><span class="p">.</span><span class="nf">instance</span><span class="p">).</span><span class="nf">to_s</span>
<span class="n">assert_equal</span> <span class="s2">"(1 . Nil)"</span><span class="p">,</span> <span class="no">List</span><span class="p">.</span><span class="nf">reverse</span><span class="p">(</span><span class="no">Cons</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="mi">1</span><span class="p">)).</span><span class="nf">to_s</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>We’re pretty confident that’s enough, even if it was kind of boring to do manually. That amount of testing would let us go home and sleep soundly.</p>
<h2 id="testing-the-quickcheck-way">Testing the QuickCheck way</h2>
<p>First, we’ll need something like QuickCheck in Ruby. The best, most idiomatic, most maintained, least-Monad-y thing I have found is <a href="https://github.com/hayeah/rantly">Rantly</a>. It has both primitive value generation built-in and property testing with shrinking. We’ll skip over the basic API and go straight to defining a property to check if my algorithm is really bullet-proof. To aid in the creation of lists from Arrays, we’ll add a new helper:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="nn">List</span>
<span class="c1"># ...</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">from_values</span><span class="p">(</span><span class="o">*</span><span class="n">values</span><span class="p">)</span>
<span class="n">values</span><span class="p">.</span><span class="nf">reverse</span><span class="p">.</span><span class="nf">inject</span><span class="p">(</span><span class="no">Nil</span><span class="p">.</span><span class="nf">instance</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">ls</span><span class="p">,</span> <span class="n">v</span><span class="o">|</span> <span class="no">Cons</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">ls</span><span class="p">)</span> <span class="p">}</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>To check that it works, let’s change the existing tests and see if they still pass:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">ListTest</span> <span class="o"><</span> <span class="no">MiniTest</span><span class="o">::</span><span class="no">Test</span>
<span class="k">def</span> <span class="nf">test_reversing_lists</span>
<span class="n">assert_equal</span> <span class="s2">"(3 . (2 . (1 . Nil)))"</span><span class="p">,</span>
<span class="no">List</span><span class="p">.</span><span class="nf">reverse</span><span class="p">(</span><span class="no">List</span><span class="p">.</span><span class="nf">from_values</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">)).</span><span class="nf">to_s</span>
<span class="n">assert_equal</span> <span class="s2">"(9 . (400 . (321 . (1 . (10 . Nil)))))"</span><span class="p">,</span>
<span class="no">List</span><span class="p">.</span><span class="nf">reverse</span><span class="p">(</span><span class="no">List</span><span class="p">.</span><span class="nf">from_values</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">321</span><span class="p">,</span> <span class="mi">400</span><span class="p">,</span> <span class="mi">9</span><span class="p">)).</span><span class="nf">to_s</span>
<span class="n">assert_equal</span> <span class="s2">"Nil"</span><span class="p">,</span> <span class="no">List</span><span class="p">.</span><span class="nf">reverse</span><span class="p">(</span><span class="no">Nil</span><span class="p">.</span><span class="nf">instance</span><span class="p">).</span><span class="nf">to_s</span>
<span class="n">assert_equal</span> <span class="s2">"(1 . Nil)"</span><span class="p">,</span> <span class="no">List</span><span class="p">.</span><span class="nf">reverse</span><span class="p">(</span><span class="no">List</span><span class="p">.</span><span class="nf">from_values</span><span class="p">(</span><span class="mi">1</span><span class="p">)).</span><span class="nf">to_s</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Run options: --seed 48889
# Running:
.
Finished in 0.001256s, 796.1783 runs/s, 3184.7134 assertions/s.
1 runs, 4 assertions, 0 failures, 0 errors, 0 skips
</code></pre></div></div>
<p>Great. Now to the newfangled thing. As I mentioned before, writing a property to check requires us to think differently than we would with regular unit tests. Your formulation should state something logical, something that does not rely on specific inputs. Following that guideline, we can reason about reversing lists in the following manner:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="c1"># ...</span>
<span class="k">def</span> <span class="nf">test_reversing_by_property</span>
<span class="n">property</span> <span class="p">{</span>
<span class="n">length</span> <span class="o">=</span> <span class="n">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1_000_000</span><span class="p">)</span>
<span class="no">List</span><span class="p">.</span><span class="nf">from_values</span><span class="p">(</span><span class="n">array</span><span class="p">(</span><span class="n">length</span><span class="p">)</span> <span class="p">{</span> <span class="n">integer</span> <span class="p">})</span>
<span class="p">}.</span><span class="nf">check</span> <span class="p">{</span> <span class="o">|</span><span class="n">list</span><span class="o">|</span>
<span class="n">assert_equal</span> <span class="n">list</span><span class="p">.</span><span class="nf">to_s</span><span class="p">,</span> <span class="no">List</span><span class="p">.</span><span class="nf">reverse</span><span class="p">(</span><span class="no">List</span><span class="p">.</span><span class="nf">reverse</span><span class="p">(</span><span class="n">list</span><span class="p">)).</span><span class="nf">to_s</span>
<span class="p">}</span>
<span class="k">end</span>
<span class="c1"># ...</span>
</code></pre></div></div>
<p>The meat is in the <code>check</code> block. Determining that a list has been reversed correctly requires us to check if reversing it again gets us back to the original list. To seed our check, we build a <code>property</code> block that creats an array with a random length between 0 and 1_000_000, itself filled with random integers. Let’s run the tests again:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ bundle exec ruby list.rb
Run options: --seed 17130
# Running:
.
..........
success: 100 tests
.
Finished in 121.969127s, 0.0164 runs/s, 0.8527 assertions/s.
2 runs, 104 assertions, 0 failures, 0 errors, 0 skips
</code></pre></div></div>
<p>It took a while (we wanted to be thorough, with those million-item arrays), but we’re pretty sure it works. I’m a believer and I’m stoked; when I look at you, however, I see a face that says “look, it’s cool and all, but isn’t it <em>kind of worthless</em>? The tests we had were telling us the same thing, and we only needed the power of our minds to generate the correct inputs. Why go through so much trouble?”</p>
<p>Well, what about those times when ours minds fail us?</p>
<h2 id="catching-a-bug-with-rantly">Catching a bug with Rantly</h2>
<p>Let’s say you’re excited about building your own data structures and want to wrap that linked list inside a very inefficient Set. You mutter to yourself that you should make sure items are not inserted twice, which for now seems to be the main difference between Sets and Lists as storage containers.</p>
<p>You build a little more structure into what you already have, adding a <code>prepend</code> method and inlining <code>reverse</code> into a <code>List</code> base class:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">List</span>
<span class="k">def</span> <span class="nf">to_s</span>
<span class="k">raise</span> <span class="s2">"Don't use this directly, fool"</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">empty?</span><span class="p">;</span> <span class="kp">true</span><span class="p">;</span> <span class="k">end</span>
<span class="k">def</span> <span class="nf">prepend</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
<span class="no">Cons</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="nb">self</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">reverse</span><span class="p">(</span><span class="n">acc</span> <span class="o">=</span> <span class="no">Nil</span><span class="p">.</span><span class="nf">instance</span><span class="p">)</span>
<span class="k">if</span> <span class="n">empty?</span>
<span class="n">acc</span>
<span class="k">else</span>
<span class="n">tail</span><span class="p">.</span><span class="nf">reverse</span><span class="p">(</span><span class="no">Cons</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">head</span><span class="p">,</span> <span class="n">acc</span><span class="p">))</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">from_values</span><span class="p">(</span><span class="o">*</span><span class="n">values</span><span class="p">)</span>
<span class="n">values</span><span class="p">.</span><span class="nf">reverse</span><span class="p">.</span><span class="nf">inject</span><span class="p">(</span><span class="no">Nil</span><span class="p">.</span><span class="nf">instance</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">ls</span><span class="p">,</span> <span class="n">v</span><span class="o">|</span> <span class="no">Cons</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">ls</span><span class="p">)</span> <span class="p">}</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">Nil</span> <span class="o"><</span> <span class="no">List</span>
<span class="kp">include</span> <span class="no">Singleton</span>
<span class="k">def</span> <span class="nf">to_s</span>
<span class="s2">"Nil"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">Cons</span> <span class="o"><</span> <span class="no">List</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">head</span><span class="p">,</span> <span class="n">tail</span> <span class="o">=</span> <span class="no">Nil</span><span class="p">.</span><span class="nf">instance</span><span class="p">)</span>
<span class="vi">@head</span> <span class="o">=</span> <span class="n">head</span>
<span class="vi">@tail</span> <span class="o">=</span> <span class="n">tail</span>
<span class="k">end</span>
<span class="nb">attr_reader</span> <span class="ss">:head</span><span class="p">,</span> <span class="ss">:tail</span>
<span class="k">def</span> <span class="nf">empty?</span><span class="p">;</span> <span class="kp">false</span><span class="p">;</span> <span class="k">end</span>
<span class="k">def</span> <span class="nf">to_s</span>
<span class="s2">"(</span><span class="si">#{</span><span class="n">head</span><span class="si">}</span><span class="s2"> . </span><span class="si">#{</span><span class="n">tail</span><span class="p">.</span><span class="nf">to_s</span><span class="si">}</span><span class="s2">)"</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>To check if an item exists, you add a <code>contains?</code> method:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">List</span>
<span class="c1"># ..</span>
<span class="k">def</span> <span class="nf">contains?</span><span class="p">(</span><span class="n">v</span><span class="p">);</span> <span class="kp">false</span><span class="p">;</span> <span class="k">end</span>
<span class="c1"># ..</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">Cons</span> <span class="o"><</span> <span class="no">List</span>
<span class="c1"># ..</span>
<span class="k">def</span> <span class="nf">contains?</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
<span class="n">head</span> <span class="o">==</span> <span class="n">v</span> <span class="o">||</span> <span class="n">tail</span><span class="p">.</span><span class="nf">contains?</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
<span class="k">end</span>
<span class="c1"># ..</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Then you write your immutable Set and matching tests:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">DumbSet</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">storage</span> <span class="o">=</span> <span class="no">Nil</span><span class="p">.</span><span class="nf">instance</span><span class="p">)</span>
<span class="vi">@storage</span> <span class="o">=</span> <span class="n">storage</span>
<span class="k">end</span>
<span class="nb">attr_reader</span> <span class="ss">:storage</span>
<span class="kp">private</span> <span class="ss">:storage</span>
<span class="k">def</span> <span class="nf">push</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
<span class="k">if</span> <span class="o">!</span><span class="n">storage</span><span class="p">.</span><span class="nf">contains?</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
<span class="no">DumbSet</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">storage</span><span class="p">.</span><span class="nf">prepend</span><span class="p">(</span><span class="n">v</span><span class="p">))</span>
<span class="k">else</span>
<span class="nb">self</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="kp">alias_method</span> <span class="ss">:<<</span><span class="p">,</span> <span class="ss">:push</span>
<span class="k">def</span> <span class="nf">contains?</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
<span class="n">storage</span><span class="p">.</span><span class="nf">contains?</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">to_a</span>
<span class="n">values</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">list</span> <span class="o">=</span> <span class="n">storage</span>
<span class="k">until</span> <span class="n">list</span><span class="p">.</span><span class="nf">empty?</span>
<span class="n">values</span> <span class="o"><<</span> <span class="n">list</span><span class="p">.</span><span class="nf">head</span>
<span class="n">list</span> <span class="o">=</span> <span class="n">list</span><span class="p">.</span><span class="nf">tail</span>
<span class="k">end</span>
<span class="n">values</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">DumbSetTest</span> <span class="o"><</span> <span class="no">Minitest</span><span class="o">::</span><span class="no">Test</span>
<span class="k">def</span> <span class="nf">setup</span>
<span class="vi">@s</span> <span class="o">=</span> <span class="p">(((</span><span class="no">DumbSet</span><span class="p">.</span><span class="nf">new</span> <span class="o"><<</span> <span class="mi">1</span><span class="p">)</span> <span class="o"><<</span> <span class="mi">2</span><span class="p">)</span> <span class="o"><<</span> <span class="mi">3</span><span class="p">)</span>
<span class="k">end</span>
<span class="nb">attr_reader</span> <span class="ss">:s</span>
<span class="k">def</span> <span class="nf">test_contains</span>
<span class="n">assert</span> <span class="n">s</span><span class="p">.</span><span class="nf">contains?</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="n">assert</span> <span class="n">s</span><span class="p">.</span><span class="nf">contains?</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="n">assert</span> <span class="n">s</span><span class="p">.</span><span class="nf">contains?</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">assert</span> <span class="o">!</span><span class="n">s</span><span class="p">.</span><span class="nf">contains?</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">test_uniqueness</span>
<span class="n">assert_equal</span> <span class="p">[</span><span class="o">-</span><span class="mi">32</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">],</span> <span class="p">(</span><span class="n">s</span> <span class="o"><<</span> <span class="o">-</span><span class="mi">32</span> <span class="o"><<</span> <span class="o">-</span><span class="mi">32</span> <span class="o"><<</span> <span class="o">-</span><span class="mi">32</span><span class="p">).</span><span class="nf">to_a</span><span class="p">.</span><span class="nf">sort</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>And because I spotted you writing new code and yelled “HEY USE RANTLY IT’S SO COOL YIPEE”, you add some property tests:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">DumbSetTest</span> <span class="o"><</span> <span class="no">Minitest</span><span class="o">::</span><span class="no">Test</span>
<span class="c1"># ...</span>
<span class="k">def</span> <span class="nf">test_contains_property</span>
<span class="n">property</span> <span class="p">{</span>
<span class="n">array</span><span class="p">(</span><span class="n">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">100</span><span class="p">))</span> <span class="p">{</span> <span class="n">integer</span> <span class="p">}</span>
<span class="p">}.</span><span class="nf">check</span> <span class="p">{</span> <span class="o">|</span><span class="n">vs</span><span class="o">|</span>
<span class="n">s</span> <span class="o">=</span> <span class="n">vs</span><span class="p">.</span><span class="nf">inject</span><span class="p">(</span><span class="no">DumbSet</span><span class="p">.</span><span class="nf">new</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">ds</span><span class="p">,</span> <span class="n">v</span><span class="o">|</span> <span class="n">ds</span> <span class="o"><<</span> <span class="n">v</span> <span class="p">}</span>
<span class="n">assert</span> <span class="n">vs</span><span class="p">.</span><span class="nf">all?</span> <span class="p">{</span> <span class="o">|</span><span class="n">v</span><span class="o">|</span> <span class="n">s</span><span class="p">.</span><span class="nf">contains?</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="p">}</span>
<span class="p">}</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">test_uniqueness_property</span>
<span class="n">property</span> <span class="p">{</span>
<span class="n">array</span><span class="p">(</span><span class="n">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">100</span><span class="p">))</span> <span class="p">{</span> <span class="n">integer</span> <span class="p">}</span>
<span class="p">}.</span><span class="nf">check</span> <span class="p">{</span> <span class="o">|</span><span class="n">vs</span><span class="o">|</span>
<span class="n">ns</span> <span class="o">=</span> <span class="n">vs</span><span class="p">.</span><span class="nf">inject</span><span class="p">(</span><span class="no">DumbSet</span><span class="p">.</span><span class="nf">new</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">ds</span><span class="p">,</span> <span class="n">v</span><span class="o">|</span> <span class="n">ds</span> <span class="o"><<</span> <span class="n">v</span> <span class="p">}</span>
<span class="n">rs</span> <span class="o">=</span> <span class="n">vs</span><span class="p">.</span><span class="nf">inject</span><span class="p">(</span><span class="n">ns</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">ds</span><span class="p">,</span> <span class="n">v</span><span class="o">|</span> <span class="n">ds</span> <span class="o"><<</span> <span class="n">v</span> <span class="p">}</span>
<span class="n">assert_equal</span> <span class="n">vs</span><span class="p">.</span><span class="nf">sort</span><span class="p">,</span> <span class="n">ns</span><span class="p">.</span><span class="nf">to_a</span><span class="p">.</span><span class="nf">sort</span>
<span class="p">}</span>
<span class="k">end</span>
<span class="c1"># ...</span>
<span class="k">end</span>
</code></pre></div></div>
<p>It looks good:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ bundle exec ruby set_test.rb
Run options: --seed 15625
# Running:
..........
success: 100 tests
..
..........
success: 100 tests
..
Finished in 0.119717s, 33.4121 runs/s, 1720.7247 assertions/s.
4 runs, 206 assertions, 0 failures, 0 errors, 0 skips
</code></pre></div></div>
<p>You then implement the removal of items:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">DumbSet</span>
<span class="c1"># ...</span>
<span class="k">def</span> <span class="nf">delete</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
<span class="n">ls</span> <span class="o">=</span> <span class="n">storage</span>
<span class="n">ns</span> <span class="o">=</span> <span class="no">DumbSet</span><span class="p">.</span><span class="nf">new</span>
<span class="k">while</span> <span class="o">!</span><span class="n">ls</span><span class="p">.</span><span class="nf">empty?</span>
<span class="k">if</span> <span class="n">ls</span><span class="p">.</span><span class="nf">head</span> <span class="o">!=</span> <span class="n">v</span>
<span class="n">ns</span> <span class="o">=</span> <span class="n">ns</span> <span class="o"><<</span> <span class="n">v</span>
<span class="k">end</span>
<span class="n">ls</span> <span class="o">=</span> <span class="n">ls</span><span class="p">.</span><span class="nf">tail</span>
<span class="k">end</span>
<span class="n">ns</span>
<span class="k">end</span>
<span class="c1"># ...</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">DumbSetTest</span> <span class="o"><</span> <span class="no">Minitest</span><span class="o">::</span><span class="no">TestCase</span>
<span class="c1"># ...</span>
<span class="k">def</span> <span class="nf">test_delete</span>
<span class="n">os</span> <span class="o">=</span> <span class="p">(((</span><span class="no">DumbSet</span><span class="p">.</span><span class="nf">new</span> <span class="o"><<</span> <span class="mi">1</span><span class="p">)</span> <span class="o"><<</span> <span class="mi">2</span><span class="p">)</span> <span class="o"><<</span> <span class="mi">3</span><span class="p">)</span>
<span class="n">ns</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="nf">delete</span><span class="p">(</span><span class="mi">1337</span><span class="p">)</span>
<span class="n">assert_equal</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">],</span> <span class="n">ns</span><span class="p">.</span><span class="nf">to_a</span><span class="p">.</span><span class="nf">sort</span>
<span class="n">ns</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="nf">delete</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="n">assert_equal</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">],</span> <span class="n">ns</span><span class="p">.</span><span class="nf">to_a</span><span class="p">.</span><span class="nf">sort</span>
<span class="n">ns</span> <span class="o">=</span> <span class="n">ns</span><span class="p">.</span><span class="nf">delete</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="n">assert_equal</span> <span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">ns</span><span class="p">.</span><span class="nf">to_a</span><span class="p">.</span><span class="nf">sort</span>
<span class="n">ns</span> <span class="o">=</span> <span class="p">(</span><span class="n">ns</span> <span class="o"><<</span> <span class="mi">432</span><span class="p">).</span><span class="nf">delete</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">assert_equal</span> <span class="p">[</span><span class="mi">432</span><span class="p">],</span> <span class="n">ns</span><span class="p">.</span><span class="nf">to_a</span><span class="p">.</span><span class="nf">sort</span>
<span class="n">ns</span> <span class="o">=</span> <span class="n">ns</span><span class="p">.</span><span class="nf">delete</span><span class="p">(</span><span class="mi">432</span><span class="p">)</span>
<span class="n">assert_equal</span> <span class="p">[],</span> <span class="n">ns</span><span class="p">.</span><span class="nf">to_a</span><span class="p">.</span><span class="nf">sort</span>
<span class="k">end</span>
<span class="c1"># ...</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Your tests pass, but this time you don’t listen to me about adding another property. You’re just not that convinced they’re worth their salt, and it looks good enough to ship with all the tests you’ve added. The Pokémon Collecting app you work on can benefit from it right now, instead of 20 minutes from now. To production it goes.</p>
<p>Time goes by, and you’ve forgotten about me and our little adventure. Your system is humming along and moved on to maintenance mode. Days have been kind of slow, so you decide to add an optimization you’ve read about in Hacker News, detailing how a node.js program got a 10x speedup. You modify your delete method accordingly:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="c1"># ...</span>
<span class="k">def</span> <span class="nf">delete</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
<span class="n">ls</span> <span class="o">=</span> <span class="n">storage</span>
<span class="n">tmp</span> <span class="o">=</span> <span class="no">DumbSet</span><span class="p">.</span><span class="nf">new</span>
<span class="k">while</span> <span class="o">!</span><span class="n">ls</span><span class="p">.</span><span class="nf">empty?</span>
<span class="k">if</span> <span class="p">(</span><span class="n">ls</span><span class="p">.</span><span class="nf">head</span> <span class="o">!=</span> <span class="n">v</span><span class="p">)</span> <span class="o">&&</span> <span class="p">(</span><span class="n">ls</span><span class="p">.</span><span class="nf">head</span> <span class="o"><</span> <span class="mi">1500</span><span class="p">)</span> <span class="c1"># secret performance trick</span>
<span class="n">tmp</span> <span class="o">=</span> <span class="n">tmp</span> <span class="o"><<</span> <span class="n">ls</span><span class="p">.</span><span class="nf">head</span>
<span class="k">end</span>
<span class="n">ls</span> <span class="o">=</span> <span class="n">ls</span><span class="p">.</span><span class="nf">tail</span>
<span class="k">end</span>
<span class="n">tmp</span>
<span class="k">end</span>
<span class="c1"># ...</span>
</code></pre></div></div>
<p>CI still reports all green.</p>
<p>A few days later, you receive a report from a User telling she deleted their Pokémon with power level 3, but her Pokémons with levels 4013, 1551 and 20000 disappeared. Your first line of defense — your tests — have not caught any issues. Sweating bullets and drowning in emails from stakeholders and other Pokémon fiends, you’re about to collapse.</p>
<p>And then you remember: what about trying to express a property to see if it holds?</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="c1"># We'll add at most 10 unique items and then delete the first</span>
<span class="c1"># 2. If there's anything wrong, this will blow up.</span>
<span class="k">def</span> <span class="nf">test_delete_property</span>
<span class="n">property</span> <span class="p">{</span>
<span class="n">array</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> <span class="p">{</span> <span class="n">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5000</span><span class="p">)</span> <span class="p">}.</span><span class="nf">uniq</span>
<span class="p">}.</span><span class="nf">check</span> <span class="p">{</span> <span class="o">|</span><span class="n">values</span><span class="o">|</span>
<span class="n">os</span> <span class="o">=</span> <span class="n">values</span><span class="p">.</span><span class="nf">inject</span><span class="p">(</span><span class="no">DumbSet</span><span class="p">.</span><span class="nf">new</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">s</span><span class="p">,</span> <span class="n">v</span><span class="o">|</span> <span class="n">s</span> <span class="o"><<</span> <span class="n">v</span> <span class="p">}</span>
<span class="n">ds</span> <span class="o">=</span> <span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="o">..</span><span class="mi">1</span><span class="p">].</span><span class="nf">inject</span><span class="p">(</span><span class="n">os</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">s</span><span class="p">,</span> <span class="n">v</span><span class="o">|</span> <span class="n">s</span><span class="p">.</span><span class="nf">delete</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="p">}</span>
<span class="n">assert_equal</span> <span class="p">(</span><span class="n">values</span><span class="p">.</span><span class="nf">size</span> <span class="o">-</span> <span class="mi">2</span><span class="p">),</span> <span class="n">ds</span><span class="p">.</span><span class="nf">to_a</span><span class="p">.</span><span class="nf">size</span>
<span class="p">}</span>
<span class="k">end</span>
</code></pre></div></div>
<p>You run it and it explodes:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ bundle exec ruby set_test.rb
Run options: --seed 46455
# Running:
..........
success: 100 tests
..
failure: 0 tests, on:
[384, 437, 120, 718, 1850, 4579, 3178, 4191, 533, 2669]
F
..........
success: 100 tests
...
Finished in 0.093858s, 63.9264 runs/s, 2248.0769 assertions/s.
1) Failure:
DumbSetTest#test_delete_property [set_test.rb:69]:
Expected: 8
Actual: 2
6 runs, 211 assertions, 1 failures, 0 errors, 0 skips
</code></pre></div></div>
<p>What? How come you’ve only got 2 when you expected 8? Well, there must be something wrong with delete, after all. Let’s take that array and try it on an <em>pry</em> session to see what happens:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[1] pry(main)> values = [384, 437, 120, 718, 1850, 4579, 3178, 4191, 533, 2669]
=> [384, 437, 120, 718, 1850, 4579, 3178, 4191, 533, 2669]
[2] pry(main)> os = values.inject(DumbSet.new) { |s, v| s << v }
=> #<DumbSet...>
[3] pry(main)> values[0..1].inject(os) { |s, v| s.delete(v) }.to_a
=> [718, 533]
</code></pre></div></div>
<p>Wait a minute! Should delete also remove everything that’s over 1000-ish? Is there anything in the code that stipulates such a thing? Maybe that node.js optimization was not so great after all. Let’s remove it and run the tests:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ bundle exec ruby set_test.rb
Run options: --seed 2727
# Running:
.
..........
success: 100 tests
..
..........
success: 100 tests
.
..........
success: 100 tests
..
Finished in 0.099329s, 60.4053 runs/s, 3120.9415 assertions/s.
6 runs, 310 assertions, 0 failures, 0 errors, 0 skips
</code></pre></div></div>
<p>Voilà: properties have saved the day, and you’ve learned not to trust Hacker News bravado ever again.</p>
<h2 id="is-using-rantly-the-same-as-using-quickcheck-or-scalacheck">Is using Rantly the same as using QuickCheck or ScalaCheck?</h2>
<p>Sort of. For one, you have to write your own generators every time you want something other than basic types, while both QuickCheck and ScalaCheck can figure out a lot by themselves. This can make expressing what you mean a lot easier, and you don’t spend time debugging your <code>property</code> blocks in search of mistakes. That said, writing a generator for your own types requires only that you instantiate them in the <code>property</code> blocks with other auto-generated values.</p>
<p>Shrinking is not as good in Rantly. It works ok a lot of the time, but it could be improved. On the surface, from skimming the algorithms used in ScalaCheck and Rantly, it doesn’t <em>seem</em> that different, but over that side of the line the patterns in minimization seem easier to spot.</p>
<p>There’s also no mechanism to test stateful code. ScalaCheck has <a href="https://github.com/rickynils/scalacheck/wiki/User-Guide#stateful-testing">Commands</a> to help in modeling state changes, and I’m aware <a href="https://github.com/manopapad/proper">PropEr</a> and <a href="http://www.quviq.com/">QuickCheck for Erlang</a> also provide something in that direction.</p>
<p>One minor thing is that integration with RSpec and MiniTest could be improved. Its output pollutes the test run, and on large suites it becomes hard to know the relationship between a failed property and a failed test. It should be easy to fix for anyone motivated. On that note, there’s no ready-made extension for MiniTest (although adding one is trivial enough that I’m sending a PR to fix it).</p>
<h2 id="final-considerations">Final considerations</h2>
<p>I hope I have proven, even if with a craptastic example, that property-testing can aid you in writing better Ruby code. Our community is great when it comes to using tests both as a design and as a verification tool, and QuickCheck (via Rantly) is a new way of thinking about them. You should keep your TDD/BDD to carve out your objects and responsibilities, but also add property checks where suitable to strengthen your confidence in the system.</p>For the past year or so I have slowly been dipping my feet into the vast functional programming seas. From taking the awesome Coursera offerings from Typesafe to slowly working through Rúnar Bjarnason’s and Paul Chiusano’s Functional Programming in Scala, my mind has been expanding proportionally to the time I dedicate to learning its ways. It has been incredibly rewarding and humbling.