<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Gabriel Lebec on Medium]]></title>
        <description><![CDATA[Stories by Gabriel Lebec on Medium]]></description>
        <link>https://medium.com/@glebec?source=rss-7b585b769590------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*SAJVujDzUrbCuVAVn0VLmg.jpeg</url>
            <title>Stories by Gabriel Lebec on Medium</title>
            <link>https://medium.com/@glebec?source=rss-7b585b769590------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 08:38:59 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@glebec/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Better JS Cases with Sum Types]]></title>
            <link>https://medium.com/fullstack-academy/better-js-cases-with-sum-types-92876e48fd9f?source=rss-7b585b769590------2</link>
            <guid isPermaLink="false">https://medium.com/p/92876e48fd9f</guid>
            <category><![CDATA[type-theory]]></category>
            <category><![CDATA[algebraic-data-types]]></category>
            <category><![CDATA[sum-types]]></category>
            <category><![CDATA[union-types]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Gabriel Lebec]]></dc:creator>
            <pubDate>Tue, 20 Feb 2018 15:59:19 GMT</pubDate>
            <atom:updated>2018-04-18T21:59:46.457Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5QHlsjm7_vkPQ7cCo62bkg.png" /></figure><p>Improving Semantics and Correctness · Illustrated via Redux State</p><h4>Abstract</h4><p>JavaScript has built-in atomic <em>scalar types, </em>such as numbers and booleans. It can also represent composite <em>product types </em>via arrays or <em>record types </em>via objects. However, it lacks an immediate solution for disjoint <em>sum types.</em> Sum types (a.k.a. tagged or discriminated unions) are a common tool in other languages; they allow a value to be one of a set of explicit cases, with easy and safe identification and data extraction. This article uses Redux state design to demonstrate common difficulties JS developers face when modeling a domain, shows how sum types mitigate those difficulties, and reviews a few libraries aiming to port sum types into the language.</p><h3>Background: Redux State</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/382/1*3WvThy5UaDcfselgJhj5Gg.png" /><figcaption><a href="https://github.com/reactjs/redux">https://github.com/reactjs/redux</a></figcaption></figure><p><a href="https://redux.js.org/">Redux.js</a> is “a predictable state container” inspired by the <a href="https://guide.elm-lang.org/architecture/">Elm Architecture</a>. A developer can represent the canonical stateful data of their application in whatever form they wish, from a sophisticated <a href="https://facebook.github.io/immutable-js/docs/#/Record">Immutable.js </a><a href="https://facebook.github.io/immutable-js/docs/#/Record">Record</a> to a straightforward POJO (Plain Old JavaScript Object). The state for an app which fetches and displays a list of adorable kittens might be as simple as:</p><pre>const initialState = {<br>  kittens: [] // no kittens fetched yet 😿<br>}</pre><p>Developers specify the state logic of a Redux-based app in a “reducer” function with the signature (oldState, action) -&gt; newState.</p><pre>function reducer (oldState, action) {<br>  if (action.type === &#39;GOT_KITTENS&#39;) {<br>    return { kittens: action.kittens } // replaces the kittens<br>  }<br>  return oldState // default, do nothing<br>}</pre><p>Given an “action” object representing an application event, the reducer determines how to produce the new state.</p><pre>newState = reducer(initialState, {<br>  type: &#39;GOT_KITTENS&#39;,<br>  kittens: [&#39;Snuggles&#39;, &#39;Mittens&#39;]<br>})</pre><pre>console.log(newState) // { kittens: [&#39;Snuggles&#39;, &#39;Mittens&#39;] } 😺</pre><p>User interface code (e.g. <a href="https://reactjs.org/">React</a> components) can subsequently read the state, creating a list of kittens.</p><pre>const currentState = reduxStore.getState()<br>const listItems = currentState.kittens.map(kitten =&gt;<br>  &lt;li&gt;{ kitten.name }&lt;/li&gt;<br>)</pre><p><em>Aside: if you have never used </em><a href="https://reactjs.org/docs/introducing-jsx.html"><em>JSX</em></a><em> before, the above might appear unsettling. This </em><a href="https://en.wikipedia.org/wiki/Domain-specific_language"><em>domain-specific language</em></a><em> compiles to vanilla JS:</em></p><pre>const currentState = reduxStore.getState()<br>const listItems = currentState.kittens.map(kitten =&gt;<br>  React.createElement(&#39;li&#39;, null, kitten.name)<br>)</pre><h3>Motivating Example: Tackling Complexity</h3><p>Initially, this direct representation of state works as expected. The application starts with no kittens. Mapping over the empty array state.kittens produces no list items, and our UI shows nothing. Later, when kitten data is fetched and the state is updated, our list will pop into view (assuming the rest of our AJAX / Redux / React code is wired correctly).</p><p>In practice, however, the user may be confused upon being shown a blank page. We really ought to let them know that the kittens are on their way:</p><pre>const kittens = reduxStore.getState().kittens</pre><pre>if (!kittens.length) { // kittens are loading?</pre><pre>  return &lt;p&gt;Calling the kittens!&lt;/p&gt;</pre><pre>} else { // kittens received, show them</pre><pre>  return (&lt;ul&gt;{<br>    kittens.map(kitten =&gt;<br>      &lt;li&gt;{ kitten.name }&lt;/li&gt;<br>    )<br>  }&lt;/ul&gt;)</pre><pre>}</pre><p>Now when the user first loads the page, they see a lovely paragraph informing them of impending kittens (how exciting!). Later, the paragraph is replaced with a list of kitten names.</p><h4>Signs of Trouble</h4><p>One day, however, a user submits a help ticket. “When I visit the kittens page, it says they are loading forever.” What went wrong?</p><p>Well, on that day, the kittens data from the server was empty. That is, [] is a valid value representing the kittens in our database. We’ve hijacked the empty array to <em>mean</em> that the kittens are still loading, but that’s not necessarily true. We started with an initial state of 0 kittens:</p><pre>{<br>  kittens: [] // intent: not yet fetched<br>}</pre><p>And then ended up with a final state of 0 kittens:</p><pre>{<br>  kittens: [] // intent: fetched (empty list from db)<br>}</pre><p>These two states are indistinguishable, though we intended them to be distinct. Our mistake was conflating <em>data </em>(the array) with <em>metadata</em> (information regarding the array).</p><h4>Falling Down the Rabbit Hole</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/660/1*0vVfO4SEhvvW1Jsp36z5mw.jpeg" /><figcaption>Alice in Wonderland, first edition. Bodleian Libraries, University of Oxford. Lewis Carroll was an accomplished mathematician as well as author.</figcaption></figure><p>As intrepid JS developers, we may next try distinguishing status based not on length, but on <em>type</em>. What if we use null to indicate unloaded kitties?</p><pre>const initialState = {<br>  kittens: null<br>}</pre><p>Unbidden, a wild error appears.</p><pre>Error: cannot read property &#39;length&#39; of null</pre><p>In a way, we got lucky this time — the code failed noisily and immediately. The problem, of course, is that null values cannot have properties, so our old UI code checking kittens.length is broken. The fix isn’t especially difficult:</p><pre>const kittens = reduxStore.getState().kittens</pre><pre>if (!kittens) { // kittens are loading</pre><pre>  return &lt;p&gt;Calling the kittens!&lt;/p&gt;</pre><pre>} else if (!kittens.length) { // kittens are loaded but empty</pre><pre>  return &lt;p&gt;Sorry, no kittens available.&lt;/p&gt;</pre><pre>} else { // kittens are loaded and can be shown</pre><pre>  return (&lt;ul&gt;{<br>    kittens.map(kitten =&gt;<br>      &lt;li&gt;{ kitten.name }&lt;/li&gt;<br>    )<br>  }&lt;/ul&gt;)</pre><pre>}</pre><p>That we have annotated the meaning of each case above should be considered a code smell; it reveals that our solution is not very semantic. Regardless, the unit tests pass, the app is deployed, and all seems well for a few days. Until…</p><h4>When Zombies Attack</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/360/1*sEcY9B9_E0AJ6s5P-Y6_nw.gif" /><figcaption><a href="https://en.wikipedia.org/wiki/One_Piece">https://en.wikipedia.org/wiki/One_Piece</a></figcaption></figure><pre>Error: cannot read property &#39;join&#39; of null</pre><p>Now what? Didn’t we solve this already? Ah, but this error is coming from <em>another </em>component:</p><pre>const kittens = reduxStore.getState().kittens</pre><pre>return &lt;p&gt;&#39;Known kittens include: &#39; + kittens.join(&#39; &amp; &#39;)&lt;/p&gt;</pre><p>Oops. Someone forgot, or was never informed, that kittens might sometimes be null. The oversight escaped attention for a while because nobody ever ran this part of the application before the kittens were fetched. It was a trap waiting for the right edge case to come along.</p><p>Over time, multiple failures like this one are added and/or discovered. As long as developers think of state.kittens semantically as a collection of kittens, they keep trying to use it as an array — even if sometimes it isn’t one.</p><h4>Out of the Frying Pan…</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/580/1*NZaNH0SFe67HtTxKrPXkAg.png" /><figcaption><a href="http://gunshowcomic.com/648">http://gunshowcomic.com/648</a></figcaption></figure><p>Fast-forward, and as product requirements have multiplied, so have the variety of ad-hoc solutions attempting to wrangle our state. The user stories now specify that kittens need to have <em>four </em>visible<em> </em>representations: unloaded, loading, fetched (with data), and failed (with an error). Across the app, similar needs are being dealt with for state.puppies and state.bunnies. Some leaves of the state tree use the strings unloaded and loading instead of the single valuenull, but that breaks some <a href="https://developer.mozilla.org/en-US/docs/Glossary/Falsy">falsy</a> checks: if (!state.bunnies) is now a mistake. The state.puppies leaf is being replaced with an Error object in the case of HTTP failure, forcing the verbose and <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof#instanceof_and_multiple_context_(e.g._frames_or_windows)">unreliable</a> check if (state.puppies instanceof Error) in the consuming code. Meanwhile, state.kittens is an object with .collection array and .isError boolean, forcing a different handling pattern — if (!state.kittens.isError) return state.kittens.collection[0]. Or maybe someone decided that some value might be false <em>or </em>null, and each stands for something different… good luck keeping them straight. With a deluge of ad-hoc reinvented cases to keep track of, developers are frequently forgetting to handle some of them, especially as the representations are inconsistent and inexpressive.</p><blockquote>“Many languages have trouble expressing data with weird shapes. They give you a small set of built-in types, and you have to represent everything with them. So you often find yourself using null or booleans or strings to encode details in a way that is quite error prone.” — <a href="https://guide.elm-lang.org/types/union_types.html">Elm Language, Union Types Documentation</a></blockquote><p>JavaScript developers often consider tackling these burdens to be a normal part of writing code. There is a common assumption that one simply must <em>be more careful</em> not to make errors like those detailed above. Losing type safety is the tradeoff one accepts in return for JS’s flexibility, right? We see examples of this all the time, especially when searching for data:</p><ul><li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf">Array.prototype.indexOf</a> returns -1 for “not found.” Not exactly clear.</li><li>Worse, <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find">Array.prototype.find</a> returns undefined for “not found;” how can we distinguish between “not found” and “found undefined?”</li><li>Sequelize’s <a href="http://docs.sequelizejs.com/manual/tutorial/models-usage.html#-find-search-for-one-specific-element-in-the-database">findById</a> method returns a promise for null when database row is not found. It’s important to remember that might be the case, or else .then(user =&gt; user.name) could one day throw an error.</li></ul><p>Programming paradigms that put the onus on human beings to be perfect inevitably result in confusion and mistakes. There must be a better way.</p><h3>Sum Types, Defined in (Informal) Theory</h3><p>The problems examined so far can be boiled down to two essential categories:</p><ul><li>No consistent and expressive way to represent separate data status cases. “Not found” ought to be <em>clearly</em> different from “found, with this data.”</li><li>A high likelihood of error when consuming data that could be in one of several forms (i.e. polymorphic). Humans focus on the ordinary case and use variables assuming they will have certain properties or methods, forgetting that the actual value may sometimes be an exceptional case.</li></ul><p>Sum types can improve both of the above. To understand sums, it helps to first examine scalar and product types.</p><h4>Scalars</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*dCZupViTuh7tyQQ1iE6QAw.png" /><figcaption>Two example scalar types. There are three scalar values of type A and two scalar values of type B.</figcaption></figure><p>A scalar type contains atomic values: single items which cannot be decomposed into parts. Examples of scalars in JavaScript include built-in types like Boolean, Number, and Null. For instance, the number 42 in JavaScript is a single value inhabiting the Number scalar.</p><p>A scalar type has an intrinsic size (a.k.a. cardinality), which is just the number of values inhabiting that type.</p><ul><li>The Boolean type has a size of 2 as it contains two values, true &amp; false.</li><li>The Number type is of “infinite” size (if we ignore the <a href="https://stackoverflow.com/a/12560672/4876305">limits</a> of <a href="https://en.wikipedia.org/wiki/IEEE_754">IEEE 754</a> ).</li><li>The <a href="http://2ality.com/2013/10/typeof-null.html">Null type</a> has a size of 1 as it contains only one value, null.</li></ul><h4>Products</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*27_a1aHVrBZnBhUv0JK6Eg.png" /><figcaption>A × B is a product of two different scalar types A and B. The size of A × B is the size of A times the size of B. Each value in A × B has both an A component and a B component.</figcaption></figure><p>Product types are composite — they consist of multiple (possibly different, possibly identical) types, grouped together in an “<strong>and</strong>” fashion. For example, a type whose values consist of two Booleans (one Bool <em>and</em> one Bool) is a product. In JavaScript, we can represent custom product types using arrays as tuples, with position serving to distinguish each member type.</p><pre>// FoodFacts are tuples of 2 bools: [isYummy, isHealthy]</pre><pre>const saladFacts   = [true, true]<br>const burgerFacts  = [true, false]<br>const vitaminFacts = [false, true]<br>const chalkFacts   = [false, false]</pre><p>Why “product?” Because the size of this new composite FoodFacts type is determined by multiplying the sizes of its constituent types. We can easily see above that there are only four different values in the type, obtained by multiplying 2 options for the first Bool × 2 options for the second Bool.</p><p>Positional notation (e.g. chalkFacts[0]) is not very clear with respect to meaning. A more expressive way to represent multiple values grouped together in JS is with objects, which can label each member value. Technically the labels make objects <em>record types </em>rather than products, but we will overlook that in this article, in the interest of making it easier to write examples:</p><pre>// Person  = { name: String, age: Number, employed: Boolean }</pre><pre>const mark = { name: &#39;Mark&#39;, age: 67, employed: false }<br>const jin  = { name: &#39;Jin&#39;,  age: 34, employed: true }<br>const ford = { name: &#39;Ford&#39;, age: 19, employed: true }<br>const sian = { name: &#39;Sian&#39;, age: 24, employed: false }<br>...</pre><p>The size of the Person type, ignoring the labels, is Infinity × Infinity × 2. That is, the infinite number of Strings, <strong>times</strong> the infinite number of Numbers, <strong>times</strong> the two possible Booleans. Clearly, we will not be able to list every possible value in the Person type.</p><h4>Sums</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*sOSLD6cvbRsqfUml_xxk5g.png" /><figcaption>A + B is a sum of two different scalar types A and B. The size of A + B is the size of A plus the size of B. Each value in A + B is either an A value or a B value.</figcaption></figure><p>If scalar type size is an intrinsic number, and the size of a product type is the product of its constituent type sizes, you will probably not be surprised to hear that the size of a sum type is the sum of its constituent type sizes. Sum types are composite like product types, but in an “<strong>or</strong>” fashion; a single value in the type is only ever <em>one of </em>the constituent types, not a grouping of them all.</p><pre>// FinitePrimitive = Boolean | Null | Undefined</pre><pre>const finitePrimitive1 = true<br>const finitePrimitive2 = false<br>const finitePrimitive3 = null<br>const finitePrimitive4 = undefined</pre><p>The FinitePrimitive type we define above has a size of 2 + 1 + 1 = 4. That is, both of the Booleans, <strong>plus</strong> the single number of Nulls, <strong>plus</strong> the single number of Undefineds. We can easily list out all four values, which we have done above. Notice, a value in this type is only <em>one of </em>the constituent types.</p><p>As another example, consider a sum type composed of some larger types:</p><pre>// InfinitePrimitive = String | Number | Symbol</pre><pre>const infinitePrimitive1 = &#39;hello&#39;<br>const infinitePrimitive2 = &#39;goodbye&#39;<br>const infinitePrimitive3 = 42<br>const infinitePrimitive4 = Symbol(&#39;hmm&#39;)<br>const infinitePrimitive5 = 314159<br>const infinitePrimitive6 = &#39;ok we get it, there are a lot of these&#39;<br>...</pre><p>The InfinitePrimitive type has a size of Infinity + Infinity + Infinity. It can be any one of the infinite strings, <strong>or</strong> one of the infinite numbers, <strong>or</strong> one of the infinite symbols.</p><h4>A Sum of Products</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*D2Q0yEwIb7Ro6iMB53VJ5g.png" /><figcaption>A + (B × B) is a sum of a scalar type and a product type. The size of A + (B × B) is the size of A, plus the size of B times the size of B. Each value in A + (B × B) is either an A value or a B × B value. B × B values have both a B component and another B component.</figcaption></figure><p>Products and sums can consist of scalars, but we didn’t define them as <em>needing</em> to consist of scalar types — on the contrary, the constituent types may themselves be products and/or sums. Here is a (non-JavaScript) sum of both scalar and product types:</p><pre>scalar type Ghost (contains one value, `ghost`)</pre><pre>product type Character { (contains 2 × 2 = 4 possible values)<br>  afraidOfNoGhosts: Boolean,<br>  ghostbuster: Boolean<br>}</pre><pre>sum type Entity = Ghost | Character</pre><p>How many values does the Entity type have? Well, it’s 1 possible Ghost value + (2 × 2) possible Character values = 5 different Entity values. Let’s enumerate them:</p><pre>entity1 = Ghost ghost<br>entity2 = Character { afraidOfNoGhosts: true, ghostbuster: true }<br>entity3 = Character { afraidOfNoGhosts: false, ghostbuster: true }<br>entity4 = Character { afraidOfNoGhosts: true, ghostbuster: false }<br>entity5 = Character { afraidOfNoGhosts: false, ghostbuster: false }</pre><h4>Tag, You’re It</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/347/1*a6DL4YDyKyDgWgvaa_1M4w.jpeg" /><figcaption><a href="https://www.tidydesign.com/blog/2012/09/free-paper-tag-image/">https://www.tidydesign.com/blog/2012/09/free-paper-tag-image/</a></figcaption></figure><p>We’ve almost finished defining sum types, but we’re missing a crucial characteristic which distinguishes them from the (very similar) <em>union</em> type. Suppose we define a sum type for name parts as being either a first name or a last name, where each is a string:</p><pre>// NamePart can be a first name string OR a last name string<br>sum type NamePart = String | String</pre><pre>namePart1 = &#39;Wilson&#39; // is this a first or last name?<br>namePart2 = &#39;Ashley&#39; // is this a first of last name?</pre><p>When we encounter a value in the wild, the fact that we know its type is String isn’t quite enough to know whether it was supposed to be from the <em>first </em>choice of NamePart strings, or the <em>second </em>choice.</p><p>For that, we need to somehow label the value — with a “<strong>tag</strong>.” The value of interest will not consist of just the string on its own, but also be accompanied by a symbolic identifier that allows the developer to know unambiguously which of the constituent types it belongs to:</p><pre>namePart1 = &lt;LastName &#39;Wilson&#39;&gt;<br>namePart2 = &lt;FirstName &#39;Ashley&#39;&gt;</pre><p>Ah, now we know exactly what roles &#39;Ashley&#39; and &#39;Wilson&#39; each play.</p><blockquote>“This overall operation is called disjoint union. Basically, it can be summarized as ‘a union, but each element remembers what set it came from’.” — <a href="https://waleedkhan.name/blog/union-vs-sum-types/">Waleed Khan, Union vs Sum Types</a></blockquote><p>If you think about it, the combination of a tag <strong>and</strong> some data is itself a product, meaning we can reframe our example sum type as a sum of products, where every product includes a tag:</p><pre>sum type NamePart = (FirstName &amp; String) | (LastName &amp; String)</pre><p>Since each tag is only one value, it doesn’t affect the size of the sum type. NamePart now has a size of (1 × Infinity) + (1 × Infinity), equivalent to its earlier size of Infinity + Infinity. Tags are therefore <em>unit types</em>.</p><p>With tags, we can now <em>discriminate </em>between otherwise identical values of a given type; the tag is a minimal form of metadata. There is a preponderance of synonyms for the concept of sum types: discriminated unions, tagged unions, disjoint unions, choice types, variants, etc.</p><p>Sum types and product types, both being composite, are also known as <a href="https://en.wikipedia.org/wiki/Algebraic_data_type">algebraic data types</a>.</p><h3>Sum Types, Defined in Practice</h3><p>We now have a loose theoretical understanding of what a sum type is, but what does one look like in actual code? For that we can turn to myriad typed languages which implement sum types as a native feature. Though they have been supported at least as far back as <a href="https://en.wikipedia.org/wiki/Tagged_union#1960s">Algol68</a>, using sum types as building blocks is especially important to many <a href="https://wiki.haskell.org/Functional_programming">functional</a> programming languages including <a href="https://www.schoolofhaskell.com/school/to-infinity-and-beyond/pick-of-the-week/sum-types">Haskell</a>, <a href="http://reasonmlhub.com/exploring-reasonml/ch_variants.html">ReasonML</a>, <a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/discriminated-unions">F#</a>, <a href="https://guide.elm-lang.org/types/union_types.html">Elm</a>, and <a href="https://doc.rust-lang.org/book/first-edition/enums.html">Rust</a>.</p><p>Let’s compare and contrast an identical sum type across a couple different languages. The stock example, used in resources like <a href="http://reasonmlhub.com/exploring-reasonml/ch_variants.html"><em>Exploring ReasonML and Functional Languages</em></a> and <a href="http://learnyouahaskell.com/making-our-own-types-and-typeclasses"><em>Learn You a Haskell for Great Good</em></a>, is Shape:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/973/1*fzJrUdhcj5xeBpAD4iroaQ.png" /></figure><ul><li>A Shape is a sum type, consisting of either a Circle <strong>or</strong> a Rectangle.</li><li>Circle tags a product type, consisting of a Point (the center location) <strong>and</strong> a Float (the radius).</li><li>Rectangle also tags a product type, consisting of a Point (one corner location) <strong>and</strong> another Point (the other corner).</li><li>A Point is a product of two Floats (x and y coordinates).</li><li>A Float is a scalar type; we will use IEEE 754 double precision floats as supplied by each language.</li></ul><h4>Shapes in ReasonML</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3_f6FWIZevHaWkTbIsFJjQ.png" /></figure><p><a href="https://reasonml.github.io/">ReasonML</a> is an impure functional, eagerly evaluated, strongly typed language with type inference. It is essentially a JavaScript-like syntax for <a href="https://ocaml.org/">OCaml</a>, which can compile to native code, JavaScript or even back to OCaml. It’s a great way for a JS native to start moving towards coding in a typed and more functional style. Sum types are referred to in ReasonML as <em>variants</em>.</p><blockquote>“Behold, the crown jewel of Reason data structures!” —<a href="https://reasonml.github.io/docs/en/variant.html">ReasonML Language, Variant Documentation</a></blockquote><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c4ba005bb4ad002d338a706c19903701/href">https://medium.com/media/c4ba005bb4ad002d338a706c19903701/href</a></iframe><p>It should be emphasized that we are <em>defining </em>shape, Circle, Rectangle, and point here. The only built-in datatype we used was float. The sum type is shape, which can be a Circle <em>or</em> a Rectangle. We also construct a couple of example shape instances using each member tag.</p><p>Perhaps confusingly, Circle can be considered a tag, a constructor function, and a type; it has properties of all three. It is used to identify a value as being from one of the shape types; that makes it a tag. It is used to create values (like circ1) in the language; that makes it a constructor. And those values consist of two other types point and float grouped together; that is a product type. We can either use Circle as the name of that product of two types, or considering the implementation details, we could say that Circle is a value of the unit type within a product of three types. Whew!</p><p>On a side note, you might have noticed at the bottom of the code snippet that ReasonML ends up representing product types (like Point) as simple arrays in JavaScript, exactly as we showed in our earlier examination of products.</p><h4>Shapes in OCaml</h4><p>ReasonML can not only compile to JS but to OCaml, making it easy to see how we would define the same entities in that language.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/73b3d137473a9992ab39c72962361c14/href">https://medium.com/media/73b3d137473a9992ab39c72962361c14/href</a></iframe><p>OCaml’s type definition syntax, freed from the burden of seeming familiar to JavaScript developers, hews much closer to the purely theoretical concept of sum and product types — even to the point of using *.</p><p>The subsequent construction of instances is quite noisy with parens, on the other hand, making it clear why OCaml is sometimes called “LISP with types”:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6c6b240f5d173c52687922c971a88d02/href">https://medium.com/media/6c6b240f5d173c52687922c971a88d02/href</a></iframe><h4>Shapes in Haskell</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/368/1*wic3qK_U5DoffX8SfAu_2w.png" /></figure><p><a href="https://www.haskell.org/">Haskell</a> is a purely functional, lazily evaluated, strongly typed language with type inference. Haskell has a heavy theoretical focus, though it is also used for practical purposes; it is very powerful yet exceptionally terse.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b68c3abb647ad77bfba7189610ff87ff/href">https://medium.com/media/b68c3abb647ad77bfba7189610ff87ff/href</a></iframe><p>Again, the only built-in datatype we used was Float. Using :type in the <a href="http://downloads.haskell.org/~ghc/latest/docs/html/users_guide/ghci.html">GHCi REPL</a> dutifully reports that yes, each example value has the type Shape. Had we added deriving (Show) to Shape, we could also log out circ1 in the REPL, which would display Circle (Point 2.0 3.0) 6.5. In short, our values “know” what types they come from and which tags they have.</p><h4>Shapes in Rust</h4><p>OK, one last example. Many of the languages that emphasize the use of sum types are dialects of, or were heavily influenced by, the <a href="https://en.wikipedia.org/wiki/ML_(programming_language)">ML</a> family of languages: ReasonML / OCaml, Standard ML, F# etc. It’s difficult to find dramatically different syntaxes for sums, which makes evolutionary sense.</p><p>Rust is a nice example as it allows the developer to define product types (as structs) and sum types (as enums) using positional or record-style notation. This isn’t unique to Rust — Haskell can do the same, for instance — but Rust’s syntax demonstrates yet more names for types. Note also how constructing instances requires using the sum type as a namespace (Shape::Circle):</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/653ac2cbb15be0aa3c0a42a03d183e53/href">https://medium.com/media/653ac2cbb15be0aa3c0a42a03d183e53/href</a></iframe><p>Don’t mistake the Rust enum for an ANSI C-style enum. The classic enumerated type is just a set of source code aliases for integers. True sum types allow the “arms” of the union to hold varied product types. Tagged unions can be implemented in C via a union of structs with an enum of tags and manual tag-checking code.</p><h4>Shapes in JavaScript, Perhaps?</h4><p>Having seen the same pattern encoded in a few languages, one might begin wondering how we can emulate it in JavaScript. The essence of sum types is that they consist of disjoint tagged types; the essence of tagging a type is to create a <strong>product</strong> of some <strong>identifier</strong> with the type. In JavaScript, a symbolic identifier with no other meaning should sound familiar; that’s a perfect use case for <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol">Symbol</a>. And we already know some ways (arrays, objects) to loosely represent products in JavaScript; even if it cheats the theory a bit (again, records are technically not products), let’s use objects for clarity.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/29a1636e080bfb5a7dc47702327d925f/href">https://medium.com/media/29a1636e080bfb5a7dc47702327d925f/href</a></iframe><p>Oof. This concrete albeit unsophisticated first-pass attempt is not only much more laborious than the previous examples we saw, it is also incomplete. We do get some of the benefits correct:</p><ul><li>Expressive construction using namespaced and named factory functions</li><li>Runtime type checks against constructor arguments</li><li>Ability to discriminate unambiguously between values based on tag</li></ul><p>On the other hand, we are missing some features:</p><ul><li><strong>We have failed to truly create a sum type</strong>, as our rectangle and circle instances <strong>do not know they are shapes</strong>! This makes it difficult to specify that a function should receive any shape. We could manually write if (arg.tag !== CircleTag &amp;&amp; arg.tag !== RectangleTag) in such a function, but that is brittle; what if we added a triangle case later?</li><li>This code pattern is itself difficult, lengthy, and error-prone to replicate in a manual, ad-hoc fashion. It is also still abusable by human developers who may try to read the center of a rectangle or corner2 of a circle.</li><li>Since JavaScript is dynamically typed, we only get failures at runtime. If a given function attempting to use a Shape is not immediately executed, we might not be aware that it contains a latent mistake.</li></ul><p>Some of these points can be mitigated. Making values “remember” their types and tags together can be accomplished using a bit more code, and making it easier to define types in this fashion can be accomplished by abstracting the definition process to a function. Publish it as a library with a small API, and we’d be well on our way to capturing many of the benefits of sum types.</p><p>However, let’s not get ahead of ourselves. Before we see some practical real-world versions of JS sum types, we need to address the other half of the equation; not only <em>constructing</em> sum type instances, but <em>consuming </em>them.</p><h3>The Payoff: Pattern Matching</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/690/1*vSBhM0jNchJkVSE3VLznYg.jpeg" /><figcaption><a href="https://jonsibal.deviantart.com/art/Superman-Secret-Origin-148465087">https://jonsibal.deviantart.com/art/Superman-Secret-Origin-148465087</a></figcaption></figure><p>By now you may be impatiently wondering what the point of all this theoretical messing about is. Recall the two problems we identified earlier: lack of a semantic way to separate cases, and human errors when using polymorphic data.</p><p>Sum types definitely solve the first problem. With the addition of a constructor tag, now every value comes with its own metadata identifier explaining just what the data’s case is.</p><p>How do we address the second problem? Ah, this is where sum types shine: <strong>pattern matching</strong>.</p><p>Pattern matching is a language-supported syntax for doing two things at once: <strong>identifying</strong> which case a value represents, and <strong>extracting </strong>the data from such a value. It lets the user of a sum type easily, declaratively, and safely consume values in the type. It prevents the user from mishandling the values by inverting control; the user no longer preemptively tries to <em>inspect</em> (potentially nonexistent) properties of an unknown type, but instead <em>provides</em> all possible type-handling cases in order to produce a result.</p><p>Let’s see pattern matching on our shapes via an example area function, with the signature Shape -&gt; Float.</p><h4>Pattern Matching in ReasonML</h4><p>A ReasonML function can directly specify that it takes a shape. How do we use the shape? By matching all the tags using switch:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/23284af1f3a47faf9c0fd0659e1099e7/href">https://medium.com/media/23284af1f3a47faf9c0fd0659e1099e7/href</a></iframe><p>When we call area at the end, passing in a circle or a rectangle, the switch will match the passed-in shape to the correct case. Note that there is no JS-style fall-through — no more than one case will ever match. We <em>should</em> provide cases for every tag; if we omit one, the compiler will actually warn us we’ve forgotten something!</p><pre>File &quot;&quot;, line 14, characters 2-90: Warning 8: this pattern-matching is not exhaustive. Here is an example of a value that is not matched: Rectangle (_, _)</pre><p>Exhaustiveness means that the function will be able to handle every value it could accept. An exhaustive function is also known as a <em>total</em> function. Non-total (i.e. <em>partial</em>) functions throw runtime errors if applied to a value they cannot handle.</p><p>Going in the other direction and attempting something nonsensical, like adding Point to our cases, stops the compiler outright:</p><pre>Line 22, 6: This variant pattern is expected to have type shape The constructor Point does not belong to type shape</pre><p>“But wait, there’s more!” Not only do we get to declaratively match to a specific case, but we can then destructure the data from that case using whatever variable names we want. The second argument of Circle is a float used for a radius; in our switch we pattern match to Circle and bind the second argument as the variable radius. We can also use _ to specify a value that we want to ignore, e.g. the center point for the circle; the area of a circle only depends on the radius after all.</p><p>Each case is a function from the matched pattern (with bindings from destructuring) to a result. In a very compact way, our code above states:</p><ul><li>if the passed-in <strong>shape</strong> is a <strong>circle</strong>,</li><li>consisting of &lt;nobody cares&gt; and a <strong>radius</strong>,</li><li>then return pi * <strong>radius</strong>²</li></ul><p>Similar logic for the Rectangle case lets us destructure the x and y coordinates of each Point in the rectangle, and do the proper math.</p><p>Pattern matching in ReasonML can get more advanced; a common tool is a fallback case if no other pattern matches, which can be enumerated as _ =&gt; (your return value here). See <a href="http://reasonmlhub.com/exploring-reasonml/ch_pattern-matching.html">here</a> for other capabilities.</p><h4>Pattern Matching in Haskell</h4><p>Haskell also has a switch syntax, called case:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8232f22ff71843d867f6593a0fe25c8a/href">https://medium.com/media/8232f22ff71843d867f6593a0fe25c8a/href</a></iframe><p>Calling area circ1 etc. in the REPL gives the expected results. Again, note that adding a nonsense case will cause the compiler to fail. Even more strict than ReasonML, <em>omitting</em> a case can also cause the compiler to fail, provided that you opt in to such behavior with the pragma {-# OPTIONS_GHC -Wincomplete-patterns -Werror #-}.</p><pre>shape.hs:25:8: warning: [-Wincomplete-patterns]<br>    Pattern match(es) are non-exhaustive<br>    In a case alternative: Patterns not matched: (Circle _ _)</pre><p>The popular <a href="https://www.schoolofhaskell.com/school/to-infinity-and-beyond/pick-of-the-week/guide-to-ghc-extensions/basic-syntax-extensions#lambdacase">LambdaCase</a> language extension lets us to skip binding a name for the shape argument:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a95dafa9901ad4683fba5d36f225aefe/href">https://medium.com/media/a95dafa9901ad4683fba5d36f225aefe/href</a></iframe><p>Haskell has other ways of defining area, including <a href="https://wiki.haskell.org/Pattern_guard">guards</a> or simply writing each case as a separate equality:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2d28dfdc2f599338a35679ef407b282e/href">https://medium.com/media/2d28dfdc2f599338a35679ef407b282e/href</a></iframe><p>Finally, Haskell allows a fallback case with otherwise.</p><h4>Pattern Matching in Rust</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8e3b253a1b54ab2f2631ca70bbfc711b/href">https://medium.com/media/8e3b253a1b54ab2f2631ca70bbfc711b/href</a></iframe><p>Rust uses the somewhat more verb-oriented keyword match to perform pattern matching. Like when constructing, Rust also requires the developer to cite which sum type the tag comes from. When destructuring arguments from a record-style product type, it uses .. to ignore unused fields. Not shown, it can use _ to ignore positional fields and also to define a fallback case.</p><p>Again, omitting or exceeding the exhaustive cases causes the compiler to fail, informing the developer that something is wrong before any code is run.</p><pre>error<a href="https://doc.rust-lang.org/error-index.html#E0004">[E0004]</a>: non-exhaustive patterns: `Rectangle(_, _)` not covered<br>  <a href="https://play.rust-lang.org/#">--&gt; src/main.rs:10:18<br></a>   |<br>10 |   return match shape_arg {<br>   |                ^^^^^^^^^ pattern `Rectangle(_, _)` not covered</pre><h3>Sum Type Feature Wishlist</h3><blockquote>“Modelling data is important for a range of reasons. From performance to correctness to safety. Tagged unions give you a way of modelling choices that forces the correct handling of them, unlike predicate-based branching, such as the one used by if statements and other common control flow structures.” — <a href="http://folktale.origamitower.com/api/v2.1.0/en/folktale.adt.union.html">Folktale Library, ADT Union Documentation</a></blockquote><p>We’ve now seen sum types defined in theory, constructed in practice, and consumed in practice. If we were to list requirements for the ideal features of a language-supported sum type, they might read as follows.</p><h4>Overall</h4><ul><li>📖 Feature a <strong>clean</strong>, <strong>expressive</strong> API</li><li>👮 <strong>Prevent</strong> naive direct inspection of data from a sum type value</li><li>✅ Enable easy <strong>type checking</strong> with an is or has function</li><li>💎 Luxury: enable <strong>extending</strong> sum types with methods</li><li>💎 Luxury: easy <strong>serialization</strong> / <strong>deserialization</strong></li></ul><h4>Definition</h4><ul><li>🖋️ Define the <strong>name</strong> of the sum type</li><li>🗄️ Define the disjoint <strong>components</strong> of a sum type</li><li>📦 Allow each component to itself be another <strong>product</strong>, <strong>sum</strong>, or <strong>scalar</strong> type</li><li>🏷️ Label each component with a <strong>tag</strong></li><li>👷 Have tags act as <strong>constructor</strong> functions, producing values from the type</li><li>📋 Enable tags to receive <strong>arguments</strong>, positionally and/or in record style</li><li>💎 Luxury: include integrated tools for working with <strong>product</strong> types</li></ul><h4>Matching</h4><ul><li>🔍 Enable <strong>matching</strong> a value to case by tag name</li><li>📜<strong> Destructure</strong> component data during the match</li><li>➡️ Map destructured data to a <strong>return value</strong> for the match expression</li><li>❓ Allow for a catch-all <strong>fallback</strong> case in the match</li><li>🚨 Ideal: fail <strong>statically</strong> if possible (during compile-time) when omitting a required case or adding an incorrect case</li><li>🚨 Compromise: barring the above, fail <strong>immediately</strong> during runtime when omitting or adding a case</li><li>🚨 Worst: barring the above, fail <strong>eventually</strong> during runtime, upon discovering that a case cannot be matched</li></ul><h3>State of the Art: JavaScript Sum Type Libraries</h3><p>Porting sum types into JS is hardly a new idea. A number of projects, some fairly prominent, have made efforts in this direction. Each implementation differs somewhat in terms of interface, capabilities, and guarantees. Below is a selection (far from exhaustive) of found examples, sorted by npm downloads per month:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/467488216a855fe99b6ca794d59b464a/href">https://medium.com/media/467488216a855fe99b6ca794d59b464a/href</a></iframe><h4><strong>Shapes in </strong>Folktale</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/848/1*8EbJP3OgMP3t8iBf5xpXUQ.png" /><figcaption><a href="http://folktale.origamitower.com/">folktale.origamitower.com</a></figcaption></figure><p>Folktale is a general-purpose functional library with other tools besides adt/union. That inflates its numbers somewhat in the above table, but it also features one of the nicest (IMHO) discussions of tagged unions, so we’ll take a look at it. The embedded code below is editable, run it yourself.</p><iframe src="https://cdn.embedly.com/widgets/media.html?url=https%3A%2F%2Frunkit.com%2Fglebec%2Fsum-type-shape-in-js-folktale-adt-union&amp;src=https%3A%2F%2Frunkit.com%2Fe%3Fname%3D7877f4b1-fe19-489d-8a68-170a68a438fb%26base64source%3DY29uc3QgdW5pb24gPSByZXF1aXJlKCdmb2xrdGFsZS9hZHQvdW5pb24vdW5pb24nKTsKCi8vIC8vIEZvbGt0YWxlIGRvZXNuJ3QgaW5jbHVkZSBhbiBleHBsaWNpdCBwcm9kdWN0IHR5cGUgYWJzdHJhY3Rpb24KLy8gY29uc3QgUG9pbnQgPSAoeCwgeSkgPT4gKHsgeCwgeSB9KQoKLy8gSG93ZXZlciwgV2UgY2FuIGZha2UgaXQgd2l0aCBhIHN1bSBvZiBvbmx5IG9uZSB0YWcuCgpjb25zdCBQb2ludCA9IHVuaW9uKCdQb2ludCcsIHsKICBQb2ludDogKHgsIHkpID0%252BICh7IHgsIHkgfSkKfSkKCi8vIEl0IGRvZXMgaW5jbHVkZSBhIHRhZ2dlZCB1bmlvbiB0eXBlIGFic3RyYWN0aW9uCi8vIE5vIGJ1aWx0LWluIGFyZ3VtZW50IHR5cGUgY2hlY2tzLCB0aG91Z2ggd2UgY2FuIGFkZCB0aGVtIHVzaW5nIHRoZSBuaWNlIGBoYXNJbnN0YW5jZWAgbWV0aG9kLgovLyBUeXBlIGNoZWNraW5nIGVsaWRlZCBmb3IgUmVjdGFuZ2xlLCB3aGljaCBpcyBkYW5nZXJvdXMuLi4KCnZhciBTaGFwZSA9IHVuaW9uKCdTaGFwZScsIHsKICBDaXJjbGU6ICAoY2VudGVyLCByYWRpdXMpID0%252BIHsKICAgIGlmICghUG9pbnQuaGFzSW5zdGFuY2UoY2VudGVyKSkgdGhyb3cgVHlwZUVycm9yKCdjZW50ZXIgbXVzdCBiZSBhIFBvaW50JykKICAgIHJldHVybiB7IGNlbnRlciwgcmFkaXVzIH0KICB9LAogIFJlY3RhbmdsZTogKGNvcm5lcjEsIGNvcm5lcjIpID0%252BICh7IGNvcm5lcjEsIGNvcm5lcjIgfSksCn0pCgovLyBQb2ludC5Qb2ludCBpcyBhIGJpdCBhd2t3YXJkLCBkdWUgdG8gc3VtIG9mIGp1c3Qgb25lIHR5cGUuCgpjb25zdCBjaXJjMSA9IFNoYXBlLkNpcmNsZShQb2ludC5Qb2ludCgyLCAzKSwgNi41KQpjb25zdCByZWN0MSA9IFNoYXBlLlJlY3RhbmdsZShQb2ludC5Qb2ludCgzLCAwKSwgUG9pbnQuUG9pbnQoMCwgMykpCgovLyBgbWF0Y2hXaXRoYCBpcyB1bmlvbidzIGNhc2UgbWF0Y2hpbmcgZnVuY3Rpb24uCi8vIFdlIGRlc3RydWN0dXJlIHRoZSBkYXRhLCBzbyBjYW4gZWFzaWx5IGlnbm9yZSB0aGUgY2lyY2xlJ3MgYGNlbnRlcmAuCi8vIEpTIG5lc3RlZCBkZXN0cnVjdHVyaW5nIGxldHMgdXMgYWxpYXMgYHhgIGZyb20gZWFjaCByZWN0YW5nbGUgcG9pbnQgYXMgYHgxYCBhbmQgYHgyYC4KCmNvbnN0IGFyZWEgPSBzaGFwZSA9PiB7CiAgaWYgKCFTaGFwZS5oYXNJbnN0YW5jZShzaGFwZSkpIHRocm93IFR5cGVFcnJvcignc2hhcGUgbXVzdCBiZSBhIFNoYXBlJykKICByZXR1cm4gc2hhcGUubWF0Y2hXaXRoKHsKICAgIENpcmNsZTogKHsgcmFkaXVzIH0pID0%252BIE1hdGguUEkgKiByYWRpdXMqcmFkaXVzLAogICAgUmVjdGFuZ2xlOiAoe2Nvcm5lcjE6IHt4OiB4MSwgeTogeTF9LCBjb3JuZXIyOiB7eDogeDIsIHk6IHkyfX0pID0%252BIHsKICAgICAgY29uc3QgaGVpZ2h0ID0gTWF0aC5hYnMoeTIgLSB5MSkKICAgICAgY29uc3Qgd2lkdGggPSBNYXRoLmFicyh4MiAtIHgxKQogICAgICByZXR1cm4gaGVpZ2h0ICogd2lkdGgKICAgIH0sCiAgICAvLyBGb286ICgpID0%252BIHt9IC8vIHRoaXMgZG9lc24ndCB0aHJvdyBhbiBlcnJvciwgZXZlbiB0aG91Z2ggaXQncyBub3QgYSBzaGFwZQogICAgLy8gQWxzbywgb21pdHRpbmcgb25lIG9mIHRoZSByZXF1aXJlZCBzaGFwZXMgZG9lc24ndCB0aHJvdyBhbiBlcnJvciBVTkxFU1Mgd2UgdHJ5IHRvIG1hdGNoIGEgbWlzc2luZyBjYXNlCiAgfSkKfQoKY29uc29sZS5sb2coYXJlYShjaXJjMSkpIC8vIDEzMi43MzIyODk2MTQxNjg3Ngpjb25zb2xlLmxvZyhhcmVhKHJlY3QxKSkgLy8gOQ%253D%253D%26minHeight%3D1050%26fixedHeight%3D1190%26location%3D%26title%3D%26oembed%3Dtrue&amp;type=text%2Fhtml&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;schema=runkit" width="900" height="1190" frameborder="0" scrolling="no"><a href="https://medium.com/media/c1ba1baf4881ec89e8f22432a5f7d466/href">https://medium.com/media/c1ba1baf4881ec89e8f22432a5f7d466/href</a></iframe><p>Biggest knock: developers can directly access .radius off of a circle. This could tempt them to try and grab .radius from an unknown shape.</p><ul><li>Lack of an integrated product type is slightly awkward but not a big deal.</li><li>Lack of mandatory declarative argument types is potentially dangerous. We can manually do the checking using static hasInstance, but that is a chore and relies on developers to dot their i’s and cross their t’s.</li><li>Using vanilla JS <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment">destructuring</a> with aliasing makes the pattern matching quite similar to the ideal.</li><li>There is no exhaustiveness check or failure on extra cases yet, though it is an active issue (<a href="https://github.com/origamitower/folktale/issues/138">Folktale #138</a>).</li><li>There is no fallback case yet, though it is an active issue (<a href="https://github.com/origamitower/folktale/issues/139">Folktale #139</a>).</li></ul><p>Folktale has other features not shown, such as <a href="http://folktale.origamitower.com/api/v2.1.0/en/folktale.adt.union.union.union.html#extending-unions"><strong>extension</strong></a> via shared <a href="http://folktale.origamitower.com/api/v2.1.0/en/folktale.adt.union.union.derive.html"><strong>derivations</strong></a> (presumably inspired by Haskell). Overall, it definitely gets us much of the way towards the ideal, but could stand to have better type safety.</p><h4>Shapes in Daggy</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/200/1*AOQnDAoCFxCm7sQnh72VPA.png" /><figcaption><a href="https://github.com/fantasyland/daggy">https://github.com/fantasyland/daggy</a></figcaption></figure><p>Daggy is part of the wider Fantasy-Land ecosystem of functional JS specs and tools. The documentation is minimal, just two barely-explained example snippets; nothing we cannot understand, however.</p><iframe src="https://cdn.embedly.com/widgets/media.html?url=https%3A%2F%2Frunkit.com%2Fglebec%2Fsum-type-shape-in-js-daggy-tagged-sum&amp;src=https%3A%2F%2Frunkit.com%2Fe%3Fname%3D2aff1036-7a90-44c1-b3eb-8314e186ee17%26base64source%3DY29uc3QgZGFnZ3kgPSByZXF1aXJlKCdkYWdneScpOwoKLy8gZGFnZ3kgaGFzIGEgc3RhbmRhbG9uZSB0YWdnZWQgcHJvZHVjdCB0eXBlCgpjb25zdCBQb2ludCA9IGRhZ2d5LnRhZ2dlZCgnUG9pbnQnLCBbJ3gnLCAneSddKQoKLy8gLi4uYW5kIGEgc3VtIHR5cGUgdG9vLgovLyBJbnN0ZWFkIG9mIGRlZmluaW5nIGNvbnN0cnVjdG9yIGxvZ2ljLCB3ZSBvbmx5IGRlY2xhcmUgcG9zaXRpb25hbCBmaWVsZHMuCi8vIEl0IGRvZXNuJ3QgbG9vayBsaWtlIHdlIGV2ZW4gaGF2ZSB0aGUgb3B0aW9uIHRvIGRvIHR5cGUgY2hlY2tpbmc%252FCgp2YXIgU2hhcGUgPSBkYWdneS50YWdnZWRTdW0oJ1NoYXBlJywgewogIENpcmNsZTogWydjZW50ZXInLCAncmFkaXVzJ10sCiAgUmVjdGFuZ2xlOiBbJ2Nvcm5lcjEnLCAnY29ybmVyMiddLAp9KQoKY29uc3QgY2lyYzEgPSBTaGFwZS5DaXJjbGUoUG9pbnQoMiwgMyksIDYuNSkKY29uc3QgcmVjdDEgPSBTaGFwZS5SZWN0YW5nbGUoUG9pbnQoMywgMCksIFBvaW50KDAsIDMpKQoKLy8gYGNhdGFgLCBzaG9ydCBmb3IgYGNhdGFtb3JwaGlzbWAsIGlzIG91ciBjYXNlIG1hdGNoaW5nIGZ1bmN0aW9uLgovLyBEYWdneSBmZWVkcyBpbiBkYXRhIHZpYSBwb3NpdGlvbmFsIGFyZ3MsIHNvIHdlIGlnbm9yZSBgQ2lyY2xlJ3NgIGZpcnN0IGFyZy4KLy8gQWx0ZXJuYXRpdmVseSwgd2UgY291bGQgaGF2ZSB0aGUgY29uc3RydWN0b3IgdGFrZSBhIHNpbmdsZSBvYmplY3QsIGFuZCBkZXN0cnVjdHVyZSBpdCBoZXJlLgoKY29uc3QgYXJlYSA9IHNoYXBlID0%252BIHsKICBpZiAoIVNoYXBlLmlzKHNoYXBlKSkgdGhyb3cgVHlwZUVycm9yKCdzaGFwZSBtdXN0IGJlIGEgU2hhcGUnKQogIHJldHVybiBzaGFwZS5jYXRhKHsKICAgIENpcmNsZTogKF8sIHJhZGl1cykgPT4gTWF0aC5QSSAqIHJhZGl1cypyYWRpdXMsCiAgICBSZWN0YW5nbGU6ICh7eDogeDEsIHk6IHkxfSwge3g6IHgyLCB5OiB5Mn0pID0%252BIHsKICAgICAgY29uc3QgaGVpZ2h0ID0gTWF0aC5hYnMoeTIgLSB5MSkKICAgICAgY29uc3Qgd2lkdGggPSBNYXRoLmFicyh4MiAtIHgxKQogICAgICByZXR1cm4gaGVpZ2h0ICogd2lkdGgKICAgIH0sCiAgICAvLyBGb286ICgpID0%252BIHt9IC8vIHRoaXMgZG9lc24ndCB0aHJvdyBhbiBlcnJvciwgZXZlbiB0aG91Z2ggaXQncyBub3QgYSBzaGFwZQogICAgLy8gQWxzbywgb21pdHRpbmcgb25lIG9mIHRoZSByZXF1aXJlZCBzaGFwZXMgZG9lc24ndCB0aHJvdyBhbiBlcnJvciBVTkxFU1Mgd2UgdHJ5IHRvIG1hdGNoIGEgbWlzc2luZyBjYXNlCiAgfSkKfQoKY29uc29sZS5sb2coYXJlYShjaXJjMSkpIC8vIDEzMi43MzIyODk2MTQxNjg3Ngpjb25zb2xlLmxvZyhhcmVhKHJlY3QxKSkgLy8gOQ%253D%253D%26minHeight%3D840%26fixedHeight%3D980%26location%3D%26title%3D%26oembed%3Dtrue&amp;type=text%2Fhtml&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;schema=runkit" width="900" height="980" frameborder="0" scrolling="no"><a href="https://medium.com/media/bc05119d6a057dda08aba37f41e4cd71/href">https://medium.com/media/bc05119d6a057dda08aba37f41e4cd71/href</a></iframe><ul><li>Biggest knock: developers can still directly access .radius off of a circle. This could tempt them to try and grab .radius from an unknown shape.</li><li>Including an integrated product type is a nice touch.</li><li>Only declaring field names is minimalist, but prevents us from even being <em>able</em> to perform type checking.</li><li>Using positional fields is more powerful than forcing destructuring, as you could always use a single field and destructure it if you wanted.</li><li>There is no exhaustiveness check or failure on extra cases, nor obvious plans to add either.</li><li>There is no fallback case, nor obvious plans to add one.</li></ul><p>Daggy allows extension through idiomatic prototypal inheritance — adding a method to Shape.prototype will allow Circles and Rectangles to delegate to that method.</p><h4>Shapes in Union-Type</h4><p>Conveniently, shape is one of the demonstrated examples from this library’s documentation (adapted slightly here).</p><iframe src="https://cdn.embedly.com/widgets/media.html?url=https%3A%2F%2Frunkit.com%2Fglebec%2Fsum-type-shape-in-js-union-type-type&amp;src=https%3A%2F%2Frunkit.com%2Fe%3Fname%3Dece6b14e-fb42-4298-b42e-7569e382a4ea%26base64source%3DY29uc3QgVHlwZSA9IHJlcXVpcmUoJ3VuaW9uLXR5cGUnKTsKCi8vIFlvdSBjYW4gZmFrZSBhIHByb2R1Y3Qgd2l0aCBhIHNpbmdsZS1jb21wb25lbnQgc3VtLgoKLy8gdW5pb24tdHlwZSBtYWtlcyB0eXBlIGNoZWNrcyByZXF1aXJlZC4KLy8gWW91IGNhbiBkZWZpbmUgYSBjdXN0b20gdmFsaWRhdG9yIG9yIHVzZSBhIGJ1aWx0LWluIGNvbnN0cnVjdG9yLiBCb3RoIGFyZSBzaG93biBoZXJlLgoKY29uc3QgaXNOdW1iZXIgPSBuID0%252BIHR5cGVvZiBuID09PSAnbnVtYmVyJwpjb25zdCBQb2ludCA9IFR5cGUoeyBQb2ludDogW2lzTnVtYmVyLCBOdW1iZXJdIH0pCgovLyBObyB0eXBlIG5hbWUgaXMgcmVxdWlyZWQuCi8vIFlvdSBjYW4gb3B0aW9uYWxseSB1c2UgcmVjb3JkIHN5bnRheC4gV2UgY2FuIGFsc28gdXNlIHByZXZpb3VzbHktZGVmaW5lZCB0eXBlcyEKCnZhciBTaGFwZSA9IFR5cGUoewogIENpcmNsZToge2NlbnRlcjogUG9pbnQsIHJhZGl1czogTnVtYmVyfSwKICBSZWN0YW5nbGU6IFtQb2ludCwgUG9pbnRdLAp9KQoKY29uc3QgcmVjdDEgPSBTaGFwZS5SZWN0YW5nbGUoUG9pbnQuUG9pbnQoMywgMCksIFBvaW50LlBvaW50KDAsIDMpKQpjb25zdCBjaXJjMSA9IFNoYXBlLkNpcmNsZShQb2ludC5Qb2ludCgyLCAzKSwgNi41KQovLyBjb25zdCBjaXJjMSA9IFNoYXBlLkNpcmNsZU9mKHsgY2VudGVyOiBQb2ludC5Qb2ludCgyLCAzKSwgcmFkaXVzOiA2LjUgfSkgLy8gYWxzbyB3b3JrcwoKLy8gdW5pb24tdHlwZSBmZWF0dXJlcyBhIGN1cnJpZWQgc3RhdGljIGBjYXNlYCBmb3IgdHlwZXMsIHdoaWNoIHZhbGlkYXRlcyB0aGUgaW5wdXQgZm9yIHVzLgovLyBSZWdhcmRsZXNzIG9mIHdoaWNoIGRlZmluaXRpb24gc3ludGF4IHdhcyB1c2VkLCB0aGUgZmllbGRzIGFyZSBzdXBwbGllZCBhcyBwb3NpdGlvbmFsIGFyZ3VtZW50cy4KCmNvbnN0IGFyZWEgPSBTaGFwZS5jYXNlKHsKICBDaXJjbGU6IChfLCByYWRpdXMpID0%252BIE1hdGguUEkgKiByYWRpdXMgKiByYWRpdXMsCiAgUmVjdGFuZ2xlOiAoW3gxLCB5MV0sIFt4MiwgeTJdKSA9PiBNYXRoLmFicyh4MiAtIHgxKSAqIE1hdGguYWJzKHkyIC0geTEpLAogIC8vIEZvbzogKCkgPT4ge30gLy8gdGhpcyBkb2Vzbid0IHRocm93IGFuIGVycm9yLCBldmVuIHRob3VnaCBpdCdzIG5vdCBhIHNoYXBlCiAgLy8gQWxzbywgb21pdHRpbmcgb25lIG9mIHRoZSByZXF1aXJlZCBzaGFwZXMgZG9lc24ndCB0aHJvdyBhbiBlcnJvciBVTkxFU1Mgd2UgdHJ5IHRvIG1hdGNoIGEgbWlzc2luZyBjYXNlCn0pCgpjb25zb2xlLmxvZyhhcmVhKGNpcmMxKSkgLy8gMTMyLjczMjI4OTYxNDE2ODc2CmNvbnNvbGUubG9nKGFyZWEocmVjdDEpKSAvLyA5%26minHeight%3D756%26fixedHeight%3D896%26location%3D%26title%3D%26oembed%3Dtrue&amp;type=text%2Fhtml&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;schema=runkit" width="900" height="896" frameborder="0" scrolling="no"><a href="https://medium.com/media/804b36956918806f3f1106ac779d1485/href">https://medium.com/media/804b36956918806f3f1106ac779d1485/href</a></iframe><ul><li>Biggest knock: developers can still directly access .radius off of a circle. This could tempt them to try and grab .radius from an unknown shape.</li><li>We are back to the slightly awkward Point.Point as there is no distinct product type.</li><li>We get all the benefits of declarative field names, <em>plus</em> validations, including declarative validations using both built-in and predefined types. Union-type does the type-checking part quite well.</li><li>Relatively seamless handling of arrays or objects in defining and constructing values for the type, albeit only positional arguments during a match.</li><li>There is no exhaustiveness check yet, though there is an issue for this (<a href="https://github.com/paldepind/union-type/issues/52">Union-Type #52</a>).</li><li>No failure on extra cases, nor obvious plans to add either.</li><li>There <strong>is</strong> a fallback case, _, though it doesn’t help for shape per se.</li></ul><p>Union-type is one of the most fully-featured examples at first glance. It includes prototypal inheritance, some fancy tools e.g. both instance and curried static case functions, variations like caseOn, recursive types, a fallback syntax and more.</p><p>Of note, one of the other libraries found (<a href="https://github.com/JAForbes/sum-type">JAForbes/sum-type</a>) was based on union-type, but with enhancements related to the <a href="https://github.com/sanctuary-js/sanctuary-def/tree/v0.14.0">sanctuary-def</a> project.</p><h4>So… Which Shall We Use?</h4><p>This is just a small selection of libraries, and the comments above are not intended to make a final judgment as to viability, implementation details, and other concerns. Rather, the intent is to see how people have attempted to solve this issue to date, and consider how we would want such a library to work. We haven’t touched on potentially important features like serialization, for example. In short, given JavaScript’s dynamically-typed nature and variety of existing edge cases, any library attempting to implement sum types is likely to have some opinions baked in, and some issues left to iron out. For instance, none of the three libraries examined prevent developers from just directly attempting to grab a property from a sum type, even if not every member of the type has that property.</p><p>For the remainder of this article, I’ll be using union-type, mostly because it includes declarative type checks and a fallback case syntax.</p><h3>Back to Redux</h3><p>An age and a half ago, this article opened with an example JavaScript use case: a Redux state tree. If you recall, we were struggling to encode various states like “unloaded,” “loading,” “loaded with data,” and “failed with an error.” It should be clear that we could represent those states as a sum type.</p><iframe src="https://cdn.embedly.com/widgets/media.html?url=https%3A%2F%2Frunkit.com%2Fglebec%2Fsum-type-shape-in-js-redux-state-leaves%2F1.0.0&amp;src=https%3A%2F%2Frunkit.com%2Fe%3Fname%3D06980a70-521b-4a32-8885-440f1e66fdd5%26base64source%3DY29uc3QgVHlwZSA9IHJlcXVpcmUoJ3VuaW9uLXR5cGUnKTsKY29uc3QgcmVkdXggPSByZXF1aXJlKCdyZWR1eCcpOwoKLy8gbmVlZGVkIHRvIGV4cGxpY2l0bHkgcGVybWl0IHBvbHltb3JwaGljIGRhdGEgaW4gdW5pb24tdHlwZQpjb25zdCBBbnkgPSAoKSA9PiB0cnVlCgovLyBUeXBlcyDigJMgZXZlcnkgbGVhZiBvZiB0aGUgc3RhdGUgdHJlZSB3aWxsIGJlIG9uZSBvZiB0aGVzZSB0eXBlcwpjb25zdCBMZWFmID0gVHlwZSh7CiAgVW5sb2FkZWQ6IFtdLAogIExvYWRpbmc6IFtdLAogIExvYWRlZDogW0FueV0sCiAgRmFpbGVkOiBbRXJyb3JdLCAvLyBtaWdodCBoYXZlIHRvIG1ha2UgdGhpcyBgYW55YCwgZ2l2ZW4gdGhhdCBKUyBjYW4gdGhyb3cgbm9uLUVycm9yc%252BKApgp9KQoKLy8gYWN0aW9uIHR5cGVzCmNvbnN0IEZFVENISU5HX0tJVFRFTlMgPSAnRkVUQ0hJTkdfS0lUVEVOUycKY29uc3QgR09UX0tJVFRFTlMgPSAnR09UX0tJVFRFTlMnCmNvbnN0IEZBSUxFRF9LSVRURU5TID0gJ0ZBSUxFRF9LSVRURU5TJwoKLy8gYWN0aW9uIGNyZWF0b3JzCmNvbnN0IGZldGNoaW5nS2l0dGVucyA9ICAgICgpID0%252BICh7IHR5cGU6IEZFVENISU5HX0tJVFRFTlMgfSkKY29uc3QgZ290S2l0dGVucyA9ICAoa2l0dGVucykgPT4gKHsgdHlwZTogR09UX0tJVFRFTlMsIGtpdHRlbnMgfSkKY29uc3QgZmFpbGVkS2l0dGVucyA9IChlcnJvcikgPT4gKHsgdHlwZTogRkFJTEVEX0tJVFRFTlMsIGVycm9yIH0pCgpjb25zdCByZWR1Y2VyID0gKG9sZFN0YXRlID0ge2tpdHRlbnM6IExlYWYuVW5sb2FkZWR9LCBhY3Rpb24pID0%252BIHsKICBzd2l0Y2ggKGFjdGlvbi50eXBlKSB7CiAgICBjYXNlIEZFVENISU5HX0tJVFRFTlM6IHJldHVybiAoeyAuLi5vbGRTdGF0ZSwga2l0dGVuczogTGVhZi5Mb2FkaW5nIH0pCiAgICBjYXNlIEdPVF9LSVRURU5TOiByZXR1cm4gKHsgLi4ub2xkU3RhdGUsIGtpdHRlbnM6IExlYWYuTG9hZGVkKGFjdGlvbi5raXR0ZW5zKSB9KQogICAgY2FzZSBGQUlMRURfS0lUVEVOUzogcmV0dXJuICh7IC4uLm9sZFN0YXRlLCBraXR0ZW5zOiBMZWFmLkZhaWxlZChhY3Rpb24uZXJyb3IpIH0pCiAgICBkZWZhdWx0OiByZXR1cm4gb2xkU3RhdGUKICB9Cn0KCmNvbnN0IHN0b3JlID0gcmVkdXguY3JlYXRlU3RvcmUocmVkdWNlcikKCmNvbnN0IGNvbnZlcnRMZWFmID0gTGVhZi5jYXNlKHsKICBVbmxvYWRlZDogICAgKCkgPT4gJ05vdGhpbmcgdG8gc2VlIGhlcmUuJywKICBMb2FkaW5nOiAgICAgKCkgPT4gJ1BsZWFzZSBiZSBwYXRpZW50LicsCiAgTG9hZGVkOiAgKGRhdGEpID0%252BIGBHb3QgdGhpcyBkYXRhOiAke2RhdGF9YCwKICBGYWlsZWQ6IChlcnJvcikgPT4gYFNvcnJ5OiAke2Vycm9yfWAsCiAgXzogICAgICAgICAgICgpID0%252BICdVaCwgaG93IGRpZCB5b3UgZXZlbiBnZXQgaGVyZT8nCn0pCgpjb25zdCBkZWJ1Z0tpdHRlbnMgPSAoKSA9PiBjb25zb2xlLmxvZyhjb252ZXJ0TGVhZihzdG9yZS5nZXRTdGF0ZSgpLmtpdHRlbnMpKQpkZWJ1Z0tpdHRlbnMoKSAvLyAiTm90aGluZyB0byBzZWUgaGVyZS4iCgpzdG9yZS5kaXNwYXRjaChmZXRjaGluZ0tpdHRlbnMoKSkKZGVidWdLaXR0ZW5zKCkgLy8gIlBsZWFzZSBiZSBwYXRpZW50LiIKCnN0b3JlLmRpc3BhdGNoKGdvdEtpdHRlbnMoWydTbnVnZ2xlcycsICdNaXR0ZW5zJ10pKQpkZWJ1Z0tpdHRlbnMoKSAvLyAiR290IHRoaXMgZGF0YTogU251Z2dsZXMsTWl0dGVucyIKCnN0b3JlLmRpc3BhdGNoKGZhaWxlZEtpdHRlbnMoRXJyb3IoJ29oIG5vZXMhJykpKQpkZWJ1Z0tpdHRlbnMoKSAvLyAiU29ycnk6IEVycm9yOiBvaCBub2VzISI%253D%26minHeight%3D1176%26fixedHeight%3D1316%26location%3D%26title%3D%26oembed%3Dtrue&amp;type=text%2Fhtml&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;schema=runkit" width="900" height="1316" frameborder="0" scrolling="no"><a href="https://medium.com/media/71b5e05112508d089357597572df6fbd/href">https://medium.com/media/71b5e05112508d089357597572df6fbd/href</a></iframe><p>If we had additional leaves in our state tree — state.bunnies, state.puppies, etc. — they would also be one of the four Leaf types. Our consuming code would use union-type’s case function to determine what UI to display.</p><p>It’s very likely that you’ve noticed something familiar about Redux’s action objects. Why… they’re just a tagged union themselves! An action can be <em>one of </em>a set number of objects, each with a type (tag), and each with potentially any number of other properties (making it a product type). In the reducer, we switch on each case based on type — <strong>#mindblown</strong>. Why not represent actions as a bona-fide sum type, then?</p><p>Unfortunately, Redux currently aggressively asserts that action objects be POJOs for now — no fancy library constructs. But the idea is sound, and in fact is precisely what inspired Redux in the first place. Redux is based on Elm, which includes tagged unions as a language feature. Recognizing that actions are members of a sum type, we have come full circle.</p><h4>Redux Conclusion</h4><p>So what have we gained? We are no longer reinventing the wheel, using primitive types to encode various mutually exclusive cases. And when we want to extract the data, we are reminded to handle every possible case. It’s not perfect — the type checks are limited, there are undoubtedly edge cases to consider, etc. And yet, the gain in both expressiveness, cleanliness, some degree of safety and more ought to be pretty appealing. Modeling your domain explicitly like this is a natural part of working with typed languages, and with all of JavaScript’s vaunted flexibility, it makes sense to adopt some of those benefits.</p><h3>Case Studies (Pun Intended)</h3><p>Redux state was a motivating example for this article, but sum types are so generally useful that it would be a shame not to go over some of their “greatest hits.” These are constructs so fundamental that they are often included in other language’s standard module. The following examples will be in pseudocode… see if you can implement them in a real language.</p><h4>Maybe / Option</h4><p>The Maybe type is either some data, or nothing at all.</p><pre>sum type Maybe = Nothing | Just anything</pre><pre>firstOfList = list =&gt;<br>    if (!list.length) return Nothing<br>    else return Just(list[0])</pre><pre>res = match firstOfList([])<br>    Nothing          =&gt; &#39;Sorry, there was nothing there.&#39;<br>    Just (something) =&gt; &#39;Ah, found something:&#39; + something</pre><pre>log(res) // &#39;Sorry, there was nothing there.&#39;</pre><p>No more -1, undefined, or null generating confusion. Methods like findIndex, find, and findById can now return a Maybe value; consuming code will then pattern match to decide what to do with the actual Nothing or Just something as the case may be. Try writing a safeDivide function which returns Nothing in case of divide by zero.</p><h4>Cons List</h4><p>This classic, recursive, closure-based, functional linked list is a workhorse of functional programming languages. Basically, a list is either the empty list Nil, or it is constructed from an element and a following list: Cons x xs.</p><pre>sum type List = Nil | Cons anything List</pre><pre>myList = Cons(1, Cons(2, Cons(3, Nil)))</pre><pre>addList = someList =&gt;<br>    match someList<br>        Nil         =&gt; 0<br>        Cons num xs =&gt; num + addList(xs)</pre><pre>log(addList(myList)) // 6</pre><h4><strong>Binary Tree</strong></h4><p>Sum types excel at processing tree structures, which is part of why they are very handy in writing compilers.</p><pre>sum type Tree = Leaf | anything Tree Tree</pre><pre>myTree = Tree(1,<br>    Tree(0, Leaf, Leaf), Tree(2,<br>         Tree(1.5, Leaf, Leaf), Tree(2.5, Leaf, Leaf)))</pre><pre>addTree = someTree =&gt;<br>    match someTree<br>        Leaf =&gt; 0<br>        Tree num left right =&gt; num + addTree(left) + addTree(right)</pre><pre>addTree(myTree) // 7</pre><h3>Conclusion</h3><p>When I started taking notes for this article, I told some friends that it would be “a quick blog post.” As it turns out, there was a lot more I wanted to say about sum types than I first realized. If you’ve made it this far, congratulations; I hope you enjoyed it and are interested to try using sum types in your next JavaScript project. The nature of the language may make the attempt imperfect, but an imperfect improvement is still an improvement. And with the possible future inclusion of <a href="https://github.com/tc39/proposal-pattern-matching">native pattern matching</a>, sum types in vanilla JS may become even more viable.</p><h4>Resources</h4><p>Here is a partial list of resources I found helpful in researching the subject, and can recommend for further reading.</p><h4>Language Documentation</h4><ul><li><a href="https://reasonml.github.io/docs/en/variant.html">ReasonML: Variant!</a> [sic]. See also <a href="http://reasonmlhub.com/exploring-reasonml/ch_variants.html">ReasonMLHub: Variant</a></li><li><a href="https://wiki.haskell.org/Algebraic_data_type">Haskell: Algebraic Data Type</a></li><li><a href="https://guide.elm-lang.org/types/union_types.html">Elm : Union Types</a></li><li><a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/discriminated-unions">F#: Discriminated Unions</a></li><li><a href="https://doc.rust-lang.org/book/first-edition/enums.html">Rust: Enums</a></li></ul><h4>JS Library Documentation</h4><ul><li><a href="http://folktale.origamitower.com/api/v2.1.0/en/folktale.adt.union.union.union.html">Folktale: Union</a> (particularly good doc-article hybrid)</li><li><a href="http://folktale.origamitower.com/api/v2.1.0/en/folktale.adt.union.union.union.html">Union-Type</a></li><li><a href="https://flow.org/en/docs/types/unions/">Flow: Unions</a></li></ul><h4>Articles &amp; Article Series</h4><ul><li><a href="https://waleedkhan.name/blog/union-vs-sum-types/">Waleed Khan, Union vs Sum Types</a>. Excellent article, really helped me understand the difference between these concepts.</li><li><a href="https://www.schoolofhaskell.com/school/to-infinity-and-beyond/pick-of-the-week/sum-types">Gabriel Gonzalez, Sum Types</a>. Examples in Haskell.</li><li><a href="https://fsharpforfunandprofit.com/series/designing-with-types.html">Scott Wlaschin, F# for Fun and Profit: Designing with Types</a>. Goes much further into how types can underpin the entire logic of an application. Also check out his <a href="https://www.youtube.com/watch?v=Up7LcbGZFuo">talk on the same subject</a>.</li><li><a href="https://codewords.recurse.com/issues/three/algebra-and-calculus-of-algebraic-data-types">Joel Burget, The Algebra (and Calculus!) of Algebraic Data Types</a>. Goes more deeply into the theoretical and mathematical aspects of ADTs.</li></ul><h4>Wikipedia</h4><ul><li><a href="https://en.wikipedia.org/wiki/Tagged_union">Tagged Union</a></li><li><a href="https://en.wikipedia.org/wiki/Algebraic_data_type">Algebraic Data Types</a></li></ul><h3>Chris Martin on Twitter</h3><p>case analysis is the best got some sum type enumerating possible states handle them all compiler makes sure basically can&#39;t fuck up</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=92876e48fd9f" width="1" height="1" alt=""><hr><p><a href="https://medium.com/fullstack-academy/better-js-cases-with-sum-types-92876e48fd9f">Better JS Cases with Sum Types</a> was originally published in <a href="https://medium.com/fullstack-academy">Fullstack Academy</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Interpreters, JITS, & Compilers (Oh My!)]]></title>
            <link>https://medium.com/fullstack-academy/interpreters-jits-compilers-oh-my-1bec4702995a?source=rss-7b585b769590------2</link>
            <guid isPermaLink="false">https://medium.com/p/1bec4702995a</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[jit]]></category>
            <category><![CDATA[v8]]></category>
            <category><![CDATA[interpreters]]></category>
            <category><![CDATA[compilers]]></category>
            <dc:creator><![CDATA[Gabriel Lebec]]></dc:creator>
            <pubDate>Fri, 09 Feb 2018 18:46:58 GMT</pubDate>
            <atom:updated>2018-03-10T15:41:50.063Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5erjNjoPi4ntvUskdqoDFQ.png" /></figure><h4>Contrasting Code Executors &amp; Translators via Concrete Examples</h4><blockquote>“I had a running compiler and nobody would touch it. …They carefully told me, computers could only do arithmetic; they could not do programs.” —<a href="https://en.wikipedia.org/wiki/Grace_Hopper">Grace Hopper</a></blockquote><p>Students learning high-level programming for the first time often struggle with differentiating the concepts of compilation and interpretation. This comes up frequently in the context of learning that <a href="https://nodejs.org/en/">Node.js</a> and Chrome both share the same <em>engine </em>— <a href="https://developers.google.com/v8/">V8</a>— which “runs” JavaScript code. A common (though not entirely correct) beginner understanding often reads as: “interpreters run the code right away, but compilers output a binary which can be executed later.” This first-pass attempt at categorization suffices early on, but confusion may ensue when the student hears of a Just-in-Time (JIT) compiler: it’s a compiler which runs the code immediately? How is that different from an interpreter? And V8 used to feature <em>two </em>compilers, but now it has an interpreter too? Oh dear.</p><p>There are plenty of excellent resources in print and online for learning compilation theory. Their focus is usually on viable techniques for handling the translation of nontrivial languages: lexing a string into a token stream → parsing tokens into a concrete or abstract syntax tree, according to a formal grammar → generating or linearizing output from the tree.</p><p>Writing a working compiler using these techniques is satisfying and illuminating, but this article takes a different tack. We will define a trivial language “QuipScript,” which can be compiled with similarly trivial logic — no parse tree in sight. We will then compare &amp; contrast running and/or translating a QS program via JS using:</p><ul><li>An <strong>interpreter</strong></li><li>A <em>Just-in-Time</em> (<strong>JIT</strong>) <strong>compiler</strong></li><li>An <em>Ahead-of-Time</em> (AOT) <strong>compiler</strong></li><li>An <em>optimizing</em> AOT <strong>compiler</strong></li></ul><p>With concrete and deliberately simple code examples, the intent is to make the differences between these approaches as intuitive as possible. Code for this article is located at <a href="https://github.com/glebec/int-jit-comp">https://github.com/glebec/int-jit-comp</a>; let’s begin.</p><h3>A Toy Language</h3><p>QuipScript is a tiny language invented for this article that builds up, modifies, and prints a single stateful string value. Here’s an example QS program:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8e79136fe847e4f55f29c8da9c089375/href">https://medium.com/media/8e79136fe847e4f55f29c8da9c089375/href</a></iframe><p>Bear in mind, a program is just a dead text file. It doesn’t necessarily do anything on its own — we need either a machine capable of using it directly, or else a system able to translate the text into something a machine can use.</p><p>This particular QS program is intended to first print “hello you”, followed by “hello world”. Take a look at the code and reason through how we get that result; it will be necessary to understand the next steps. When you’re ready, move on for a brief explanation.</p><p>Every QS program has a single implicit stateful string which begins empty. In this example, we first concatenate hello and then you into the string. Next, we print the current state of the string. Afterwards, we remove the last three letters, concat them, remove those four letters, concat world!, and remove the last letter. Our string state is now hello world — which we print.</p><h3>Interpreter</h3><p>Our QS code is certainly quite lovely (<em>cough</em>), but it’s useless without a way to make a computer execute it. As knowledgeable JavaScript programmers, however, it shouldn’t be too difficult to write a program which:</p><ol><li>Reads in the text file as a string</li><li>Separates the string into lines</li><li>Identifies the intent of each line</li><li>Executes the specified logic in JavaScript, live</li></ol><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2c310c7e6ec5da02f909dbcf4a1cefc4/href">https://medium.com/media/2c310c7e6ec5da02f909dbcf4a1cefc4/href</a></iframe><p>This is a QS interpreter, written in JS. Every statement in the QS code is read in and identified. When the JS code has determined the purpose of a QS statement, it executes the logic itself, <em>in situ</em>.</p><p>Running node interpreter.js produces the following output in our terminal:</p><pre>hello you<br>hello world</pre><p>Just as we wanted.</p><p>What if our source QS file had an error partway through — but <em>after</em> the first call to print? We might see output like this:</p><pre>hello you<br>/Users/glebec/dev/compilers-article/interpreter.js:25<br>  default: throw Error(&#39;unexpected token: &#39; + line);<br>           ^</pre><pre>Error: unexpected token: ERROR I AM AN INVALID LINE OF GSCRIPT CODE<br>    at sourceCode.split.forEach.line (/Users/glebec/dev/compilers-article/interpreter.js:25:18)</pre><p>Notice that hello you was printed before we reached the erroneous line of QS code. Interpreters merrily execute portions of source code as they go, meaning that they might perform some work before failing.</p><p>Interpreters generally have the following aims:</p><ul><li>Begin running <strong>immediately</strong></li><li><strong>Produce results</strong> <em>while </em>analyzing source code</li><li>Fail “<strong>close to</strong>” the error location</li></ul><h4>Caveat</h4><p>Our QuipScript interpreter, written in JavaScript, can run statement by statement. This was easy since every QS statement conveniently maps 1-to-1 with an equivalent JS statement. A less contrived source language however might first require parsing into an intermediate language or tree representation in order to be correctly and/or efficiently interpreted.</p><h3>Just-in-Time (JIT) Compiler</h3><p>Our interpreter worked by figuring out the semantic intent of our QS code, and then realizing that intent <em>itself</em> as it read through the source. But that is not the only way we could have generated our final result.</p><p>As an alternative, we could <strong>compile</strong> (translate) our <em>source</em> QS code into <em>target</em> (or <em>object</em>) JS code — building up a program string. We won’t run each statement live, but rather wait until we have generated an entire JS program:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3209cccd2afa3bf16a7293667627bb0f/href">https://medium.com/media/3209cccd2afa3bf16a7293667627bb0f/href</a></iframe><p>Provided there are no errors, the entire QS program will be converted into a JS program, <em>before any source logic is actually executed</em>. We finally use JavaScript’s (very dangerous) eval function to run our generated JS code.</p><p>Running the above code with node jit.js logs the following to our terminal:</p><pre>hello you<br>hello world</pre><pre>FYI, here is the compiled program:</pre><pre>let string = &#39;&#39;;<br>string += &#39;hello&#39;;<br>string += &#39; you&#39;;<br>console.log(string);<br>string = string.slice(0, -3);<br>string += &#39;them&#39;;<br>string = string.slice(0, -4);<br>string += &#39;world!&#39;;<br>string = string.slice(0, -1);<br>console.log(string);</pre><p>It’s important to understand that the main output (hello you…) is not printed until the eval line runs. The generated JS program is also printed here just for demonstration purposes — in a real JIT we obviously would not embed the compiled code in the program output.</p><p>The main takeaway is that a compiler converts the input program into an equivalent target language program. A JIT compiler usually has these aims:</p><ul><li>To compile the entire source code to object code <strong>ASAP</strong></li><li>To <strong>subsequently run</strong> the object code, when it is possible to do so</li></ul><p>Because our example compiler does not execute any source logic itself, if our source code includes a syntax error, the compiler will fail <em>before</em> any results are output (since the object code is never run):</p><pre>/Users/glebec/dev/compilers-article/jit.js:31<br>  default: throw Error(&#39;unexpected token: &#39; + line);<br>           ^</pre><pre>Error: unexpected token: ERROR I AM AN INVALID LINE OF GSCRIPT CODE<br>    at sourceCode.split.forEach.line (/Users/glebec/dev/compilers-article/jit.js:31:18)</pre><p>Notice, no hello you was printed this time.</p><p>Logically, it should make sense that an interpreter begins outputting results earlier than a JIT compiler. However, one would imagine that once the JIT has finished compiling, the generated JS program might theoretically run faster than the interpreter, which has to loop through and analyze each line. In our toy language example this might not be the case, but for more complex languages, interpreting the code is likely going to run slower than executing the compiled code.</p><h4>Caveat</h4><p>In reality, there are various more advanced flavors of JIT which combine the concepts of compilers &amp; interpreters, compiling and running target code <em>while</em> parsing the source code. Some may also be capable of monitoring the running code and re-compiling source as necessary.</p><p>Many definitions of JIT outright require some or all of these additional capabilities. This article uses a more primitive distinction however, and separates JIT from AOT (see next section) based solely on whether the target code is immediately executed by the time it is done compiling.</p><h3>Ahead-of-Time (AOT) Compiler</h3><p>If we wanted to re-run our QS code, we could pass it through either the interpreter or JIT again. But then we’d be re-doing all the work from scratch. Wouldn’t it make sense to compile <em>once</em>, ahead of time, and simply save the generated JS program for future use?</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7867896453d6faedb84363e1a6d056f8/href">https://medium.com/media/7867896453d6faedb84363e1a6d056f8/href</a></iframe><p>This code is identical to the JIT above, except at the very end. Instead of immediately evaling our constructed JS program string, we save it to a file. So, running node compiler.js creates a new file (hello-world.js) for us to use in the future.</p><p>Subsequently entering node hello-world.js produces the expected output:</p><pre>hello you<br>hello world</pre><p><em>(Debug code truncated, as it is identical to the JIT example above.)</em></p><p>The advantage is clear: from now on, we don’t repeat work. We can run this output JS code as often as we want, and it will both start up immediately (like an interpreter) and run quickly (like a JIT). The downside is we had to produce the JS file before actually using it.</p><h3>Optimizing AOT Compiler</h3><p>If we are front-loading the work of compiling our source code (QS) to object code (JS), why are we allowing the JS to be so inefficient? Remember, our primitive compilers above generate the following JS program string/file:</p><pre>let string = &#39;&#39;;<br>string += &#39;hello&#39;;<br>string += &#39; you&#39;;<br>console.log(string);<br>string = string.slice(0, -3);<br>string += &#39;them&#39;;<br>string = string.slice(0, -4);<br>string += &#39;world!&#39;;<br>string = string.slice(0, -1);<br>console.log(string);</pre><p>It isn’t hard to see that we could write a much simpler program in JS that accomplishes the same task. If only our compiler could intelligently do some of the work in advance, optimizing away inefficiencies:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5a7a5481cbe6583313992810c26c64c2/href">https://medium.com/media/5a7a5481cbe6583313992810c26c64c2/href</a></iframe><p>This compiler is doing a bit of the work itself, finding ways of simplifying the program. When we use it via node opt-compiler.js, it saves the following code as hello-world.js:</p><pre>console.log(&#39;hello you&#39;)<br>console.log(&#39;hello world&#39;)</pre><p>Ah, much better! Running this code via node hello-world.js will give us exactly the results we want, with no superfluous string manipulation.</p><p>Doing the extra logic to generate this simplified code means an optimizing compiler might take longer than a JIT to compile, but the resultant JS code is even more efficient when actually run. In general, AOT compilers have the following aims:</p><ul><li>Analyze the code as <strong>deeply as possible</strong>, looking for optimizations.</li><li>Generate output code which is <strong>fast</strong> (to run), <strong>small</strong> (on disk), and/or <strong>lean</strong> (in terms of memory use); priorities are not always mutually compatible.</li><li><strong>Save</strong> the generated code for future use, baking in improvements.</li></ul><h4>Optimizations</h4><p>The “optimization” shown in this example was practically interpretation itself, but optimizations take many forms, including:</p><ul><li><strong>Dead code elimination</strong> — if some source code could logically never be useful, remove it from the output. For example, if we did some more concatenation after the final print, that would be pointless work.</li><li><strong>Register allocation</strong> — the most used variables might be stored closer to the processor (e.g. in explicit registers), so they do not have to be retrieved from higher layers (e.g. RAM).</li><li><strong>Loop unrolling</strong> — if the number of passes of a loop can be analyzed ahead of time, a loop can be converted into a simple sequence of statements with no expensive “jump” commands or control flow statements.</li><li><strong>Inlining</strong> — if a variable is used just to name some constant data reused across the app, the compiler can simply replace the variable with the data in the output code (saving a memory lookup).</li></ul><p>That’s just a small sampling; modern compilers analyzing well-designed languages can perform other sophisticated optimizations and static checks.</p><h3>Case Study: V8</h3><p>Google’s V8 Engine is the core of the Chrome browser and Node.js runtime environment. It is the code which reads your JS file and executes the logic within. So, how does V8 work? Is it an interpreter, a JIT, an AOT compiler, or something else entirely?</p><p>As it turns out, this is an area in which V8 is actively evolving. Let’s take a simplified look at both how it used to work and also the more recent pipeline.</p><h4>Old Way: JIT + Optimizing Compiler</h4><p>From 2010 to 2017, V8 used <strong>two</strong> compilers: a <em>lazy </em>JIT named Full-Codegen, and an optimizing compiler (either the earlier Crankshaft or later Turbofan). When V8 executed some JS, it would go through the following steps:</p><ol><li>The JIT would analyze the JS and compile it to <em>machine code </em>for your particular platform. This takes a short period of time — longer than an interpreter takes to start, but generally short enough for humans not to care, often because the browser is still downloading other page elements. Interestingly, Full-Codegen would compile <em>lazily</em> — not converting everything at once, but targeting individual functions as needed.</li><li>The machine code would then be immediately executed by the runtime environment. Running machine code is much more efficient than interpreting JS. In the interest of getting your code to run ASAP, however, the JIT made little to no optimizations, so the machine code is not as fast as it could be.</li><li>As the machine code ran, V8 would profile it and identify hotspots — functions that are called frequently, potential bottlenecks to performance.</li><li>V8’s optimizing compiler (Crankshaft or Turbofan) would then kick in and re-translate those functions (from JS to machine code) in a more intensive way. This process is slower than JIT compilation, but the resulting machine code is faster to run.</li><li>V8 finally live-substituted in the newly-optimized machine code, straight into your running program. The performance of a script would improve while it was being used. Quite a neat trick!</li></ol><h4>New Way: Compiler + Interpreter + Optimizing Compiler</h4><p>In 2017, V8 <a href="https://v8project.blogspot.com/2017/05/launching-ignition-and-turbofan.html">switched over</a> to a new pipeline prominently featuring (drumroll)… an interpreter!? Yes, it may seem surprising, but the newest component, named Ignition, has some key advantages.</p><p>The trick is that Ignition does not interpret <em>JavaScript</em> per se, but rather a compiled intermediate language between JS and machine code — a platform-agnostic <em>bytecode</em>. Bytecode is essentially a formal pseudocode, taking the form of a low-level instruction set for a purely hypothetical processor. Because this deliberately generic language is similar to the assembly languages used in most modern computers, it is easy to take one last step and convert it into actual machine code for a given platform. One only needs to tweak the text to account for the local dialect, as it were.</p><p>So, V8’s newest pipeline actually features an (unnamed) JS-to-bytecode compiler, the Ignition bytecode interpreter, and the Turbofan optimizing compiler. When this system receives a JS file, the following occurs:</p><ol><li>V8 compiles the source JS into generic bytecode, identical for every platform (not specific to a given OS or processor). The compiler uses a few “easy” optimizations in this step, so the bytecode is already fairly efficient.</li><li>Now, the Ignition interpreter begins executing the compiled bytecode. It may be slightly slower than running compiled machine code directly, but is still pretty fast.</li><li>Again, hotspots are identified and re-compiled using the Turbofan optimizing compiler. However, this time the optimization doesn’t start from scratch with JS, but proceeds from the already-generated bytecode.</li></ol><p>At first glance, it is perhaps not obvious what advantages this new system confers. Can compiling to semi-optimized bytecode, and then <em>interpreting</em> that bytecode, be comparable to just doing a JIT compilation to machine code?</p><p>In fact, Ignition is quite close in execution speed to Full-Codegen, and the V8 developers reap the following rewards:</p><ul><li>Faster startup times, mostly because it is quicker to compile to bytecode than it is to fully compile the source JS to machine code.</li><li>Significantly less memory use, because most of the source JS can now be “thrown away” after conversion to bytecode. This is especially good for mobile platforms, a major motivation behind Ignition’s development.</li><li>Simpler integration with the Turbofan optimizing compiler, both speeding up the optimization step and making it easier to implement new JS language features (from ECMAScript) as they are published.</li></ul><p>The moral of this story is that the archetypal view of interpreters resulting in slow runtime execution and compilers generating fast runtime execution can become muddied, or at least nuanced, when more complex hybrid solutions are considered.</p><h3>Aside: WebAssembly</h3><p>Having examined the differences between AOT and JIT compilation, you may very well ask: why don’t people compile their JS ahead of time, with an optimizing compiler? Wouldn’t that yield the best possible results?</p><p>The short answer is that it would be nice, and that’s how <em>native</em> apps work. A user downloads a precompiled binary for their OS and runs it directly. However, it’s not entirely feasible for the web, for the following reasons:</p><ul><li>Not all browsers are built on Chrome’s virtual machine. If websites had to serve up pre-compiled JS code to clients, they’d need multiple versions for different browsers and operating systems. Instead, all that browsers currently need is a single JS file. Different engines, e.g. SpiderMonkey (Firefox), Chakra (MS Edge), and JavaScriptCore (Safari) may interpret or JIT compile that JS, and they might compile it to bytecode or machine code. But in every case, JS is the <em>lingua franca</em> from which more vendor- and platform-specific results can be generated.</li><li>For security reasons, it would be a bad idea to let browsers execute pre-compiled native code, which might read or write private data in the file system or perform other nefarious acts. By limiting browsers to JS, developers are restricted to only the APIs and capabilities that JS as a language affords (and which the browser grants).</li></ul><p>However, the potential performance benefits of compiled code have not been overlooked. The W3C has designed a universal binary object code language for the internet, called <a href="http://webassembly.org/">WebAssembly</a>. The promise of WASM is to provide nearly-native performance in a low-level, pre-compiled format, which is still secure and safe to be run by browsers (due to restricted capabilities).</p><p>Modern browsers are already supporting WASM, though JS is still needed e.g. to manipulate the DOM. Developers can write code in languages like C or Rust and compile to WASM modules which are loaded and invoked by JS. WASM therefore can greatly speed up certain kinds of calculations, working alongside JS to provide a more performant web.</p><h3>Conclusion</h3><p>This article is intended as a high-level introduction to lessen confusion among those encountering these concepts for the first time. The code snippets are not meant to demonstrate recommendable or effective techniques for use in real interpreters or compilers. However, it is my hope that these deliberately simple scripts might illuminate the core differences between these entities. Here is a summary of what we illustrated through examples:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/df2bf968a4c1c2d2f1b424aba0f5dc86/href">https://medium.com/media/df2bf968a4c1c2d2f1b424aba0f5dc86/href</a></iframe><p>It should also be evident that performing optimizations is not limited strictly to AOT compilers. A JIT can also perform some optimizations, so long as they do not slow down the compilation process too much. However, an AOT can afford to take as much time as it needs to generate the best possible result.</p><p>We also saw that more sophisticated pipelines may involve techniques such as lazy compilation, compilation to intermediate representations, dynamic re-compilation, and other hybrid approaches.</p><h4>Additional Resources</h4><p>If you want to learn more about this interesting and deep topic, here are some relevant resources:</p><ul><li>[GitHub] <a href="https://github.com/glebec/int-jit-comp">glebec/int-jit-comp</a> (repository of runnable code examples from this article)</li><li>[Amazon] Aho et al., <a href="https://www.amazon.com/Compilers-Principles-Techniques-Tools-2nd/dp/0321486811">Compilers: Principles, Techniques, and Tools (2nd ed.)</a> <em>(known as the “dragon book”, a classic text)</em></li><li>[YouTube] McIlroy et al., <a href="https://www.youtube.com/watch?v=r5OWCtuKiAk">Ignition: an Interpreter for V8</a> (with <a href="https://docs.google.com/presentation/d/1OqjVqRhtwlKeKfvMdX6HaCIu9wpZsrzqpIVIwQSuiXQ/edit#slide=id.g1357e6d1a4_0_58">slides</a>)</li><li>[YouTube] Hinkelmann, <a href="https://www.youtube.com/watch?v=p-iiEDtpy6I">JavaScript Engines — How Do They Even?</a></li><li>[V8 Blog] Clifford, <a href="https://v8project.blogspot.com/2017/05/launching-ignition-and-turbofan.html">Launching Ignition and Turbofan</a></li><li>[StackOverflow] Mittag, <a href="https://softwareengineering.stackexchange.com/a/269878">Understanding the Differences</a></li></ul><h4>Addendum</h4><ul><li>[Medium] Hinkelmann, <a href="https://medium.com/dailyjs/understanding-v8s-bytecode-317d46c94775">Understanding V8’s Bytecode</a></li></ul><h3>Fedor Indutny on Twitter</h3><p>If you&#39;re curious about doing JIT assembly in JS, there is a very old blog post that may still work (or not): https://t.co/7YxmHXyTOE https://t.co/ZTeIY6g94a</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1bec4702995a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/fullstack-academy/interpreters-jits-compilers-oh-my-1bec4702995a">Interpreters, JITS, &amp; Compilers (Oh My!)</a> was originally published in <a href="https://medium.com/fullstack-academy">Fullstack Academy</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Thunks in Redux: The Basics]]></title>
            <link>https://medium.com/fullstack-academy/thunks-in-redux-the-basics-85e538a3fe60?source=rss-7b585b769590------2</link>
            <guid isPermaLink="false">https://medium.com/p/85e538a3fe60</guid>
            <category><![CDATA[redux-saga]]></category>
            <category><![CDATA[redux-observable]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[redux]]></category>
            <category><![CDATA[redux-thunk]]></category>
            <dc:creator><![CDATA[Gabriel Lebec]]></dc:creator>
            <pubDate>Mon, 30 Oct 2017 06:59:26 GMT</pubDate>
            <atom:updated>2017-11-02T15:47:18.285Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*uI9EcXQnWX-bG8uv3kTSgg.png" /></figure><h4>What Thunks Are, What They Solve, &amp; Other Options</h4><p>This article was born as a gist for <a href="https://facebook.github.io/react/">React</a> &amp; <a href="http://redux.js.org/">Redux</a> beginners, intended to demystify what thunks are and the motivation for using them.</p><p>Redux was created by <a href="https://github.com/gaearon">Dan Abramov</a> for a <a href="https://www.youtube.com/watch?v=xsSnOQynTHs">talk</a>. It is a “state container” inspired by the unidirectional <a href="http://facebook.github.io/flux/">Flux</a> data flow and functional <a href="https://github.com/evancz/elm-architecture-tutorial/">Elm</a> architecture. It provides a predictable approach to managing state that benefits from immutability, keeps business logic contained, acts as the single source of truth, and has a very small API.</p><p>The synchronous and pure flow of data through Redux’s components is well-defined with distinct, simple roles. Action creators create objects → objects are dispatched to the store → the store invokes reducers → reducers generate new state → listeners are notified of state updates.</p><p>However, Redux is not an application framework, and does not dictate how effects should be handled. For that, developers can adopt any preferred strategy through <em>middleware</em>.</p><blockquote>I’d probably let action creator return a function. If it’s a function, it’s given dispatch and the state. — <a href="https://github.com/reactjs/redux/issues/1#issuecomment-107603703"><em>Dan Abramov</em></a><em>, responding to issue #1 in Redux.</em></blockquote><p><a href="https://github.com/gaearon/redux-thunk">Redux-Thunk</a> is arguably the most primitive such middleware. It is certainly the first that most people learn, having been written by Dan Abramov as <a href="https://github.com/reactjs/redux/issues/1">part of Redux proper</a> before being <a href="https://github.com/gaearon/redux-thunk/commit/f8d41b003221c270639cdd8eba19f8e9a141b53d">split out</a> into a separate package. That original implementation is tiny enough to quote in its entirety:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9ea4ebdf2364c3163695d61b65ae76f8/href">https://medium.com/media/9ea4ebdf2364c3163695d61b65ae76f8/href</a></iframe><p>Since then, the Redux-Thunk source code has only expanded to <a href="https://github.com/gaearon/redux-thunk/blob/41aefcc28a80d2b21f8ee1e68639757bf6d7ba49/src/index.js">fourteen lines total</a>. Despite this apparent simplicity, however, thunks still engender occasional confusion. If you find the concept fuzzy, fear not! We shall begin by answering a common question…</p><h3>What are Thunks?</h3><p>The precise definition of a “thunk” varies across contexts. Generally though, thunks are a functional programming technique used to delay computation. Instead of performing some work <em>now</em>, you produce a function body or unevaluated expression (the “thunk”) which can optionally be used to perform the work <em>later</em>. Compare:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/21a5d2ef4eb50d7677deafde159c06c2/href">https://medium.com/media/21a5d2ef4eb50d7677deafde159c06c2/href</a></iframe><p>Named functions help to highlight the thunk, but the distinction is made clearer using arrows. Notice how a thunk (the function returned from thunkedYell(…)) requires an extra invocation before the work is executed:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b6d2c674f5dee1246191fb74dd82cdaf/href">https://medium.com/media/b6d2c674f5dee1246191fb74dd82cdaf/href</a></iframe><p>Here the potential work involves a side effect (logging), but thunks can also wrap calculations that might be slow, or even unending. In any case, other code can subsequently decide whether to actually run the thunk:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c9619ae0469864765459cbedf13d9b10/href">https://medium.com/media/c9619ae0469864765459cbedf13d9b10/href</a></iframe><h4>Aside: Laziness</h4><p><a href="https://en.wikipedia.org/wiki/Lazy_evaluation">Lazy</a> languages like <a href="http://learnyouahaskell.com/introduction">Haskell</a> treat function arguments as thunks <a href="https://wiki.haskell.org/Thunk">automatically</a>, allowing for “infinite” computed-on-demand lists and clever compiler optimizations. Laziness is a powerful technique which can be implemented in JavaScript via various approaches and language features, including <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get">getters</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy">proxies</a>, and <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*">generators</a>. For example, the <a href="https://github.com/chalk/chalk">Chalk</a> library <a href="https://github.com/chalk/chalk/blob/539231341426d4b3951b062e806123137b452bf7/index.js#L59">uses a getter</a> to lazily build infinite property chains: chalk.dim.red.underline.bgBlue etc. On the mathematical front, there is a thunked version of the famous <a href="https://en.wikipedia.org/wiki/Fixed-point_combinator#Fixed_point_combinators_in_lambda_calculus">Y combinator</a>, called (aptly enough) the <a href="https://en.wikipedia.org/wiki/Fixed-point_combinator#Strict_fixed_point_combinator">Z combinator</a>, which can be run in eager languages like JavaScript.</p><p>Laziness is a large topic deserving its own article. Rather than explore thunks and laziness in general, the remainder of this post will focus on <a href="https://github.com/gaearon/redux-thunk">redux-thunk</a>.</p><h4>Thunks in React &amp; Redux</h4><p>In React / Redux, thunks enable us to avoid <em>directly</em> causing side effects in our actions, action creators, or components. Instead, anything impure will be wrapped in a thunk. Later, that thunk will be invoked by middleware to actually cause the effect. By transferring our side effects to running at a single point of the Redux loop (at the middleware level), the rest of our app stays relatively pure. Pure functions and components are easier to reason about, test, maintain, extend, and reuse.</p><h3>Fundamentals &amp; Motivation</h3><p>Redux store.dispatch expects to be applied to an &quot;action&quot; (object with type):</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/58bc8a7d1128645baa13d744e0e44902/href">https://medium.com/media/58bc8a7d1128645baa13d744e0e44902/href</a></iframe><p>Because manually writing action objects in multiple places is a potential source of errors (what if we accidentally wrote userr instead of user?), we prefer &quot;action creator&quot; functions that always return a correctly-formatted action:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b43ef54033352f36214f3f15377171d1/href">https://medium.com/media/b43ef54033352f36214f3f15377171d1/href</a></iframe><h4>Problem</h4><p>However, if we have to do some async, such as an AJAX call via the <a href="https://github.com/axios/axios">axios</a> library, a simple action creator no longer works.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f1ecd55f6aa8043b63284f0fb64e8450/href">https://medium.com/media/f1ecd55f6aa8043b63284f0fb64e8450/href</a></iframe><p>The problem is that asyncLogin no longer returns an action object. How could it? The payload data (user object) isn&#39;t available yet. Redux (specifically, dispatch) doesn&#39;t know how to handle promises – at least, not on its own.</p><h4>First Thought: Call Async Directly</h4><p>We <em>could</em> do a store.dispatch ourselves in the async handler:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6f2a07dc08f71c587e872802ec915514/href">https://medium.com/media/6f2a07dc08f71c587e872802ec915514/href</a></iframe><p>This seems ok at first glance. However, it presents several cons.</p><h4>Con A: Inconsistent API</h4><p>Now our components <em>sometimes</em> call store.dispatch(syncActionCreator()), and <em>sometimes</em> call doSomeAsyncThing().</p><ul><li>In the latter case, it’s not obvious that we are dispatching to the store. We cannot identify Redux actions at a glance, making our app’s data flow more opaque.</li><li>What if we later change an action-function from sync to async, or async to sync? We have to track down and modify the call site for that function, in every single component it is used. Yuck!</li></ul><p>What we want is a way to still use store.dispatch(actionCreator()), even for async actions.</p><h4>Con B: Impurity</h4><p>The asyncLogin function isn&#39;t pure; it has a side effect (network call). Of course eventually we must make that call, and we&#39;ll see a solution soon. But side effects embedded in a component make that component harder to work with and reason about. For example, in unit testing, you may have to intercept or modify axios otherwise the component will make actual network calls.</p><h4>Con C: Tight Coupling</h4><p>The asyncLogin function is tightly coupled to a specific store in scope. That isn&#39;t reusable; what if we wanted to use this action creator with more than one Redux store, e.g. for server-side rendering? Or no real store at all, e.g. using a mock for testing?</p><h4>Better: Thunks (Initial Attempt)</h4><p>Enter thunks. Instead of making the network call <em>now</em>, you return a function which can be executed at will <em>later</em>.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8e9026d09ed195ec742694d31df55a5f/href">https://medium.com/media/8e9026d09ed195ec742694d31df55a5f/href</a></iframe><p>We’re back to a single API style, and our action creator thunkedLogin is pure, or at least “purer”: when invoked, it returns a function, performing no <em>immediate</em> side effect.</p><p><em>“But wait,”</em> an astute reader might object. <em>“That action creator returns a function, which subsequently gets </em><em>dispatched (last line). I thought Redux only understands action objects? Also, this is still tightly coupled!&quot;</em></p><p>Correct. If this was our only change, the thunk would be passed into our Redux reducers, uselessly. Thunks are not magic, and insufficient on their own. Some additional code will need to actually invoke the thunk. That brings us to our next tool: whenever a value gets dispatched to the Redux store, it first passes through <em>middleware</em>.</p><h3>Redux-Thunk Middleware</h3><p>The redux-thunk middleware, once <a href="https://github.com/gaearon/redux-thunk#installation">installed</a>, does essentially the following:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/955e205c9005708c4ef9186da6b27321/href">https://medium.com/media/955e205c9005708c4ef9186da6b27321/href</a></iframe><ul><li>If a normal action object is dispatched, redux-thunk simply passes it along (e.g. into the reducer), as if redux-thunkdid not exist.</li><li>If a function (e.g. a thunk) is dispatched, redux-thunk calls that function, passing in the store&#39;s dispatch and getState. It does not forward the thunk to the reducer.</li></ul><p>Just what we needed! Now our action creators can return objects <strong>or</strong> functions. In the former case, everything works as normal. In the latter case, the function is intercepted and invoked.</p><p>When our example thunk is invoked by the middleware, it performs an asynchronous effect. <em>When that async is complete,</em>the callback or handler can dispatch a normal action to the store. Thunks therefore let us “escape” the normal Redux loop temporarily, with an async handler eventually re-entering the loop.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QERgzuzphdQz4e0fNs1CFQ.gif" /><figcaption>Image source: <a href="http://slides.com/jenyaterpil/redux-from-twitter-hype-to-production">http://slides.com/jenyaterpil/redux-from-twitter-hype-to-production</a></figcaption></figure><h4>Dependency Injection</h4><p>We have seen that thunks in Redux let us use a unified API and keep our action creators pure. However, our demonstration still used a specific store. The redux-thunk middleware gives us a way to solve that issue: <a href="https://en.wikipedia.org/wiki/Dependency_injection">dependency injection</a>. DI is one technique for mitigating code coupling; instead of code knowing how to <em>pull in</em> a dependency (and therefore being tightly coupled to it), the dependency is <em>provided to</em> the code (and can therefore be easily swapped). This role reversal is an example of the more general concept of <a href="https://msdn.microsoft.com/en-us/library/ff921087.aspx">inversion of control</a>.</p><p>Thunks generally take no arguments — they are latent computations, ready to be performed with no further input. However, redux-thunk bends that rule, and actually passes two arguments to the thunk: dispatch and getState. Our standard pattern for defining thunked action creators will therefore not need a scoped store:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ef61b97869ced42356f59a36424aafaa/href">https://medium.com/media/ef61b97869ced42356f59a36424aafaa/href</a></iframe><p>How does this work? Where does this new dispatch argument come from?</p><p>The short answer is that the redux-thunk middleware has access to the store, and can therefore pass in the store&#39;s dispatch and getState when invoking the thunk. The middleware itself is responsible for <em>injecting</em> those dependencies into the thunk. The action creator module does not need to retrieve the store manually, so this action creator can be used for different stores or even a mocked dispatch.</p><h4>getState</h4><p>We did not show using getState in the thunk, as it is easy to abuse. In most Redux apps, it is more properly the responsibility of <em>reducers</em> (not actions) to use previous state to determine new state. There may be some cases in which reading the state inside a thunk is defensible, however, so be aware it is an option. Dan Abramov addresses <a href="https://stackoverflow.com/a/35674575/4876305">using state in action creators</a>:</p><p><a href="https://stackoverflow.com/questions/35667249/accessing-redux-state-in-an-action-creator/35674575#35674575">Accessing Redux state in an action creator?</a></p><blockquote>The few use cases where I think it’s acceptable is for checking cached data before you make a request, or for checking whether you are authenticated (in other words, doing a conditional dispatch)<em> — </em><a href="https://stackoverflow.com/a/35674575/4876305"><em>Dan Abramov</em></a></blockquote><h4>withExtraArgument</h4><p><em>“But wait, there’s more!”</em> Not only does Redux-Thunk inject dispatch and getState, it can also inject any custom dependencies you want, using <a href="https://github.com/gaearon/redux-thunk#injecting-a-custom-argument">withExtraArgument</a>. So if we wanted to inject axios, letting it be more easily mocked out for testing, we could.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e66d32185ae9a6edce178388e1caca49/href">https://medium.com/media/e66d32185ae9a6edce178388e1caca49/href</a></iframe><p>At a certain point, one wonders where the dependency injection should stop. Is <em>no</em> code allowed to pull in dependencies? Is there a better way? DI and IoC are useful, but <a href="https://medium.com/javascript-scene/mocking-is-a-code-smell-944a70c90a6a">perhaps not ideal</a>. Again, be aware of the option, but consider whether it is truly necessary for your application.</p><h3>Why Thunk Middleware, and not Promise Middleware?</h3><p>Promises are composable representations of asynchronous values, which have become native and widespread in JavaScript. The <a href="https://github.com/acdlite/redux-promise">redux-promise</a> and <a href="https://github.com/pburtchaell/redux-promise-middleware">redux-promise-middleware</a> packages enable dispatching promises or action objects containing promises. Both have some good capabilities and make handling async in Redux somewhat more convenient. However, neither addresses the issue of impurity. Promises are <em>eager</em>; they represent an async action that has <em>already been initiated</em> (in contrast to a <a href="http://folktale.origamitower.com/api/v2.0.0/en/folktale.concurrency.task.html">Task</a>, which is like a lazy Promise – user code is not actually executed unless you call run.)</p><h4>Naive Promises Use</h4><p>An initial attempt at using promises (without thunks) in Redux might appear as follows:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/447b8fd9e1bba88d3a5b03d7d35fa4d2/href">https://medium.com/media/447b8fd9e1bba88d3a5b03d7d35fa4d2/href</a></iframe><p>Look closely; this is essentially our “Call Async Directly” idea again. The promiseLogin function eventually dispatches an action from within a success handler. We are <em>also</em> dispatching the initial promise to the store, but what would any potential middleware do with that promise? At best, we&#39;d want a hypothetical redux-promise-naive middleware to discard the promise so it doesn&#39;t end up in the reducer. That&#39;s doable, but overlooks some issues:</p><ul><li>Again, calling async code immediately makes our component / action-creator impure, which is difficult to work with and test.</li><li>Our promiseLogin is still coupled to a specific store, reducing reusability.</li><li>It can be tricky to distinguish a promise object from an action object. <a href="https://promisesaplus.com/">P/A+ promises</a> have a painstaking <a href="https://promisesaplus.com/#the-promise-resolution-procedure">[[promiseResolutionProcedure]]</a> for duck-typing promises safely. The foolproof way to deal with this uncertainty is to coerce values using Promise.resolve, but doing so for every Redux action is a bit heavy-handed.</li></ul><h4>Smarter Promise Usage</h4><p>The real redux-promise and redux-promise-middleware packages are smarter than our hypothetical redux-promise-naive. They allow dispatching promises or actions with promise payloads, and when the promise is fulfilled, the middleware will dispatch a normal action. For example:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6299577689ed2f6cd0b6bf4c05e88b46/href">https://medium.com/media/6299577689ed2f6cd0b6bf4c05e88b46/href</a></iframe><p>Here, redux-promise-middleware will detect the explicitly declared payload.promise in a dispatched action. It prevents this action from going directly to the reducer, and automatically dispatches a separate &#39;LOGIN_PENDING&#39; action instead. It then waits for the promise to settle, at which point it dispatches a &#39;LOGIN_FULFILLED&#39; or &#39;LOGIN_REJECTED&#39; action with the payload replaced by the promise&#39;s value or reason. That&#39;s a nice mix of actions we get for free, facilitating UI features like loading spinners or error notifications.</p><p>This middleware offers one improvement: promiseLogin no longer depends on a particular store. Rather, the middleware takes care of dispatching the final data to the store itself.</p><p>Unfortunately, redux-promise-middleware still hasn&#39;t contained the side effect; promiseLogin makes a network call immediately. This is arguably the Achilles&#39; heel of promise-based redux middleware, and our components are back to being impure and needing some kind of hook or modification for testing purposes or reuse in other contexts.</p><h4>Thunked Promises</h4><p>As it turns out, nothing prevents us from <a href="https://github.com/pburtchaell/redux-promise-middleware/blob/master/docs/guides/chaining-actions.md">using </a><a href="https://github.com/pburtchaell/redux-promise-middleware/blob/master/docs/guides/chaining-actions.md">redux-promise-middleware <em>alongside</em> </a><a href="https://github.com/pburtchaell/redux-promise-middleware/blob/master/docs/guides/chaining-actions.md">thunk-middleware</a>. By delaying the creation of the promise, we gain both the laziness of thunks and the automatic action dispatching of redux-promise-middleware:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/71b2119a08f1335e3d04f8bb4322f06a/href">https://medium.com/media/71b2119a08f1335e3d04f8bb4322f06a/href</a></iframe><p>At this point, the simple core concept of thunks is beginning to be buried under complexities of debatable necessity. Do we really need two middleware libraries and to remember to use specific code patterns just to handle effects in Redux? We will examine a few alternatives shortly. Before then, there is one last note we ought to cover regarding promises and thunks.</p><h4>Returning Promises from Thunks</h4><p>When using redux-thunk, if a dispatched thunk returns a promise then dispatch will <em>also</em> return that same promise:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f1570ca981eaa4c015465413e4b11079/href">https://medium.com/media/f1570ca981eaa4c015465413e4b11079/href</a></iframe><p>Once again, it is easy to abuse this pattern. One generally seeks to keep React components as pure as possible; adding async handlers back into them feels like a step backwards. It also makes our API inconsistent again.</p><p>However, there are a number of times and places where using a returned promise from a dispatch call can be nice. CassioZen presents a few in his <a href="https://www.youtube.com/watch?v=xihoZZU0gao">ReactCasts #10: Redux Thunk Tricks</a> video.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FxihoZZU0gao%3Ffeature%3Doembed&amp;url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DxihoZZU0gao&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FxihoZZU0gao%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/9587b4539aa21466499e4dc9d3a65370/href">https://medium.com/media/9587b4539aa21466499e4dc9d3a65370/href</a></iframe><h3>Alternatives to Thunks</h3><h3>Dan Abramov on Twitter</h3><p>This is my karmic payback for redux-thunk</p><p>So, are thunks the <strong>One True Way</strong> to manage async / side effects in Redux applications? Certainly not. We already mentioned promise-based middleware. Thunks have at least one benefit over promises, but the below packages may be more convenient for certain use cases.</p><ul><li><a href="https://github.com/acdlite/redux-promise">Redux-Promise</a></li><li><a href="https://github.com/pburtchaell/redux-promise-middleware">Redux-Promise-Middleware</a></li><li>(2017–11–02<em> addendum:</em><a href="https://github.com/lelandrichardson/redux-pack"><em> Redux-Pack</em></a><em> also merits consideration</em>)</li></ul><p>Also, thunks are among the simplest of approaches. For any more complex asynchronicity, thunks can result in a lot of manual callback logic. More sophisticated, expressive, and composable solutions exist. The most established at this time, from most to least used, are:</p><ul><li><a href="https://github.com/redux-saga/redux-saga">Redux-Saga</a>, based on <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*">generator functions</a></li><li><a href="https://github.com/redux-observable/redux-observable">Redux-Observable</a>, based on <a href="http://reactivex.io/rxjs/">RxJS observables</a></li><li><a href="https://github.com/redux-loop/redux-loop">Redux-Loop</a>, modeled after <a href="https://guide.elm-lang.org/architecture/effects/">Elm’s effect system</a></li></ul><p>Redux-Saga uses generators, a native feature all JavaScript developers ought to master. The remainder of Redux-Saga’s API is ad-hoc / unique, so while you may pick it up quickly, the knowledge is not as portable. It is especially nice for testing, however, as sagas return simple descriptions of desired effects, instead of functions which perform those effects.</p><p>In comparison, Redux-Observable is built on RxJS, a large library with a longer learning curve. However, RxJS is useful outside of Redux-Observable as a powerful and composable way to manage asynchronicity.</p><p>Redux-Loop is not as widespread, but follows Redux itself in being inspired by Elm. It is interesting for focusing not on action creators but rather reducers; this keep the state logic more central and contained.</p><p>These and other considerations make choosing between sagas, observables, loops, and any other options a matter of use case and preference, with no universal winner.</p><h3>Conclusion</h3><p>Ultimately, thunks are an effective solution for applications with simple async requirements. Understanding thunks is an approachable goal for those learning Redux the first time. Once you become comfortable with them, it’s a good idea to try alternatives.</p><h4>Additional Resources</h4><ul><li><a href="https://github.com/gaearon/redux-thunk">Redux-Thunk Docs</a></li><li><a href="https://egghead.io/lessons/javascript-redux-dispatching-actions-asynchronously-with-thunks">Dan Abramov: explaining thunks</a></li><li><a href="https://www.youtube.com/watch?v=xihoZZU0gao">CassioZen: ReactCasts #10: Redux Thunk Tricks</a></li><li><a href="https://stackoverflow.com/questions/35411423/how-to-dispatch-a-redux-action-with-a-timeout/35415559#35415559">Dan Abramov: why you might or might not need thunks</a></li><li><a href="https://stackoverflow.com/a/35674575/4876305">Dan Abramov: using state in action creators</a></li><li><a href="http://blog.isquaredsoftware.com/2017/01/idiomatic-redux-thoughts-on-thunks-sagas-abstraction-and-reusability/">Mark Erikson: Idiomatic Redux: Thoughts on Thunks, Sagas, Abstraction, and Reusability</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=85e538a3fe60" width="1" height="1" alt=""><hr><p><a href="https://medium.com/fullstack-academy/thunks-in-redux-the-basics-85e538a3fe60">Thunks in Redux: The Basics</a> was originally published in <a href="https://medium.com/fullstack-academy">Fullstack Academy</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>