<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nicola Todorov</title>
    <description>The latest articles on DEV Community by Nicola Todorov (@todoniko).</description>
    <link>https://dev.to/todoniko</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3284689%2Ff7a201b5-4585-451d-b0e1-406b8176f394.png</url>
      <title>DEV Community: Nicola Todorov</title>
      <link>https://dev.to/todoniko</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/todoniko"/>
    <language>en</language>
    <item>
      <title>Designing with Product and Sum types</title>
      <dc:creator>Nicola Todorov</dc:creator>
      <pubDate>Fri, 04 Jul 2025 21:08:10 +0000</pubDate>
      <link>https://dev.to/todoniko/designing-with-product-and-sum-types-2m1i</link>
      <guid>https://dev.to/todoniko/designing-with-product-and-sum-types-2m1i</guid>
      <description>&lt;h2&gt;
  
  
  Composing types
&lt;/h2&gt;

&lt;p&gt;In the previous article about opaque types we touched upon the idea of &lt;strong&gt;make illegal states unrepresentable&lt;/strong&gt; by asking the simple question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Are all possible &lt;code&gt;String&lt;/code&gt; values a valid email address?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The same question can be asked for more complex types. Those that are   composed of other types.&lt;/p&gt;

&lt;p&gt;For example how are we going to model playing card?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;Face&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Ace&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Two&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Three&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Four&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Five&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Six&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Seven&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Eight&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Nine&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Ten&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Jack&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Queen&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;King&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;Suit&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Diamond&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Heart&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Club&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Spade&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Card&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@Nonnull&lt;/span&gt; &lt;span class="nc"&gt;Face&lt;/span&gt; &lt;span class="n"&gt;face&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;@Nonnull&lt;/span&gt; &lt;span class="nc"&gt;Suit&lt;/span&gt; &lt;span class="n"&gt;suit&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Product type
&lt;/h2&gt;

&lt;p&gt;Types that encode &lt;strong&gt;and&lt;/strong&gt; relationship we call product types. In the card example we have a type that contains a &lt;code&gt;Face&lt;/code&gt; &lt;strong&gt;and&lt;/strong&gt; a &lt;code&gt;Suit&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There is another way to look at the type. We can think of it as a description of a set of values. Then we can measure the size/cardinality of that set. I annotate size/cardinality of &lt;code&gt;Type&lt;/code&gt; as &lt;code&gt;|Type|&lt;/code&gt;&lt;br&gt;
For example: &lt;br&gt;


&lt;/p&gt;
&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;∣Face∣=13∣Suit∣=4∣Card∣=∣Face∣∗∣Suit∣=13∗4=52
\begin{align*}
|Face|&amp;amp;=13 \newline
|Suit|&amp;amp;=4 \newline
|Card|&amp;amp;=|Face| * |Suit| \newline 
      &amp;amp;= 13*4=52
\end{align*}
&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mtable"&gt;&lt;span class="col-align-r"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;span class="mord mathnormal"&gt;F&lt;/span&gt;&lt;span class="mord mathnormal"&gt;a&lt;/span&gt;&lt;span class="mord mathnormal"&gt;ce&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;span class="mord mathnormal"&gt;S&lt;/span&gt;&lt;span class="mord mathnormal"&gt;u&lt;/span&gt;&lt;span class="mord mathnormal"&gt;i&lt;/span&gt;&lt;span class="mord mathnormal"&gt;t&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;span class="mord mathnormal"&gt;C&lt;/span&gt;&lt;span class="mord mathnormal"&gt;a&lt;/span&gt;&lt;span class="mord mathnormal"&gt;r&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="col-align-l"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;13&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;span class="mord mathnormal"&gt;F&lt;/span&gt;&lt;span class="mord mathnormal"&gt;a&lt;/span&gt;&lt;span class="mord mathnormal"&gt;ce&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;∗&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;span class="mord mathnormal"&gt;S&lt;/span&gt;&lt;span class="mord mathnormal"&gt;u&lt;/span&gt;&lt;span class="mord mathnormal"&gt;i&lt;/span&gt;&lt;span class="mord mathnormal"&gt;t&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;13&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;∗&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;4&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;52&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;



&lt;p&gt;Hence the name Product type. If it is not clear why we multiply the size, think of all possible inputs that &lt;code&gt;Card&lt;/code&gt; can accept.&lt;/p&gt;

&lt;p&gt;But how is that useful?&lt;/p&gt;

&lt;p&gt;Well we know that all playing cards are exactly 52 and the cardinality of the &lt;code&gt;Card&lt;/code&gt; type is 52 so there is nothing to worry about - all possible inputs create valid playing card.&lt;/p&gt;

&lt;p&gt;How about if we want jokers as well? Who doesn't like jokers?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Card&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@Nonnull&lt;/span&gt; &lt;span class="nc"&gt;Face&lt;/span&gt; &lt;span class="n"&gt;face&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;@Nonnull&lt;/span&gt; &lt;span class="nc"&gt;Suit&lt;/span&gt; &lt;span class="n"&gt;suit&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;isJoker&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;No brainer, right?&lt;/p&gt;

&lt;p&gt;Let's calculate the cardinality of &lt;code&gt;Card&lt;/code&gt; though.&lt;br&gt;

&lt;/p&gt;
&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;∣Card∣=∣Face∣∗∣Suit∣∗∣Boolean∣=13∗4∗2=104
\begin{align*}
|Card|&amp;amp;=|Face| * |Suit| * |Boolean| \newline 
      &amp;amp;= 13 * 4 * 2 = 104
\end{align*}
&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mtable"&gt;&lt;span class="col-align-r"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;span class="mord mathnormal"&gt;C&lt;/span&gt;&lt;span class="mord mathnormal"&gt;a&lt;/span&gt;&lt;span class="mord mathnormal"&gt;r&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="col-align-l"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;span class="mord mathnormal"&gt;F&lt;/span&gt;&lt;span class="mord mathnormal"&gt;a&lt;/span&gt;&lt;span class="mord mathnormal"&gt;ce&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;∗&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;span class="mord mathnormal"&gt;S&lt;/span&gt;&lt;span class="mord mathnormal"&gt;u&lt;/span&gt;&lt;span class="mord mathnormal"&gt;i&lt;/span&gt;&lt;span class="mord mathnormal"&gt;t&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;∗&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;span class="mord mathnormal"&gt;B&lt;/span&gt;&lt;span class="mord mathnormal"&gt;oo&lt;/span&gt;&lt;span class="mord mathnormal"&gt;l&lt;/span&gt;&lt;span class="mord mathnormal"&gt;e&lt;/span&gt;&lt;span class="mord mathnormal"&gt;an&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;13&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;∗&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;4&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;∗&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;2&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;104&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
Our possible instances are way bigger than the expected 54 cards - 52 playing cards and 2 jokers.&lt;br&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Card&lt;/span&gt; &lt;span class="n"&gt;illegal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Card&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Face&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Two&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Suit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Spades&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;One may argue that this is not illegal card because it is stating which card is being substituted by the joker. However this encoding does not represent our domain correctly. We can reach out to &lt;em&gt;smart constructors&lt;/em&gt; to solve this, but we have something more powerful.&lt;/p&gt;
&lt;h2&gt;
  
  
  Sum types
&lt;/h2&gt;

&lt;p&gt;Types that encode &lt;strong&gt;or&lt;/strong&gt; relationship we call sum types. Your intuition might be I am talking about &lt;code&gt;enum&lt;/code&gt;s like &lt;code&gt;Face&lt;/code&gt;, but those are crippled version of sum type.&lt;br&gt;
Look.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;Face&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Ace&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Two&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Three&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Four&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Five&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Six&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Seven&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Eight&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Nine&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Ten&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Jack&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Queen&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;King&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;Suit&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Diamond&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Heart&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Club&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Spade&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;JokerColor&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Red&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Black&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;sealed&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Card&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;PlayingCard&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@Nonnull&lt;/span&gt; &lt;span class="nc"&gt;Face&lt;/span&gt; &lt;span class="n"&gt;face&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;@Nonnull&lt;/span&gt; &lt;span class="nc"&gt;Suit&lt;/span&gt; &lt;span class="n"&gt;suit&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Card&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Joker&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@Nonnull&lt;/span&gt; &lt;span class="nc"&gt;JokerColor&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Card&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We have two types of &lt;code&gt;Card&lt;/code&gt; either &lt;code&gt;PlayingCard&lt;/code&gt; &lt;strong&gt;or&lt;/strong&gt; &lt;code&gt;Joker&lt;/code&gt;. Each variant accepts different type of arguments - better than &lt;code&gt;enum&lt;/code&gt;s, no?&lt;/p&gt;

&lt;p&gt;Since we are calling it sum type it is kind of obvious how are we going to calculate cardinality. Let's compute. &lt;/p&gt;


&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;∣Card∣=∣PlayingCard∣+∣Joker∣=∣Face∣∗∣Suit∣+∣JokerColor∣=13∗4+2=54
\begin{align*}
 |Card| &amp;amp;= |PlayingCard| + |Joker| \newline 
        &amp;amp;= |Face| * |Suit| + |JokerColor| \newline 
        &amp;amp;= 13 * 4 + 2 = 54
\end{align*}
&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mtable"&gt;&lt;span class="col-align-r"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;span class="mord mathnormal"&gt;C&lt;/span&gt;&lt;span class="mord mathnormal"&gt;a&lt;/span&gt;&lt;span class="mord mathnormal"&gt;r&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="col-align-l"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;span class="mord mathnormal"&gt;Pl&lt;/span&gt;&lt;span class="mord mathnormal"&gt;a&lt;/span&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="mord mathnormal"&gt;in&lt;/span&gt;&lt;span class="mord mathnormal"&gt;g&lt;/span&gt;&lt;span class="mord mathnormal"&gt;C&lt;/span&gt;&lt;span class="mord mathnormal"&gt;a&lt;/span&gt;&lt;span class="mord mathnormal"&gt;r&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;span class="mord mathnormal"&gt;J&lt;/span&gt;&lt;span class="mord mathnormal"&gt;o&lt;/span&gt;&lt;span class="mord mathnormal"&gt;k&lt;/span&gt;&lt;span class="mord mathnormal"&gt;er&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;span class="mord mathnormal"&gt;F&lt;/span&gt;&lt;span class="mord mathnormal"&gt;a&lt;/span&gt;&lt;span class="mord mathnormal"&gt;ce&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;∗&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;span class="mord mathnormal"&gt;S&lt;/span&gt;&lt;span class="mord mathnormal"&gt;u&lt;/span&gt;&lt;span class="mord mathnormal"&gt;i&lt;/span&gt;&lt;span class="mord mathnormal"&gt;t&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;span class="mord mathnormal"&gt;J&lt;/span&gt;&lt;span class="mord mathnormal"&gt;o&lt;/span&gt;&lt;span class="mord mathnormal"&gt;k&lt;/span&gt;&lt;span class="mord mathnormal"&gt;er&lt;/span&gt;&lt;span class="mord mathnormal"&gt;C&lt;/span&gt;&lt;span class="mord mathnormal"&gt;o&lt;/span&gt;&lt;span class="mord mathnormal"&gt;l&lt;/span&gt;&lt;span class="mord mathnormal"&gt;or&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;13&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;∗&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;4&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;2&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;54&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;



&lt;p&gt;While it might not feel like big accomplishment that we are combining sum and product types, notice that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we can not produce invalid &lt;code&gt;Card&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;we introduced zero logic&lt;/li&gt;
&lt;li&gt;domain is communicated clearly - meaning vs encoding&lt;/li&gt;
&lt;li&gt;the compiler will ensure that everybody complies with the domain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's see how we can extend this list with&lt;/p&gt;

&lt;h2&gt;
  
  
  State machines
&lt;/h2&gt;

&lt;p&gt;For that we will need slightly more complex problem. We will continue with cards. But this time we need &lt;code&gt;Deck&lt;/code&gt; of &lt;code&gt;Card&lt;/code&gt;s:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we can have initial &lt;code&gt;Deck&lt;/code&gt; as if it is brand new one&lt;/li&gt;
&lt;li&gt;we can have shuffled &lt;code&gt;Deck&lt;/code&gt; that is  ... well shuffled&lt;/li&gt;
&lt;li&gt;and last but not least we can have empty &lt;code&gt;Deck&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Expected behavior for a &lt;code&gt;Deck&lt;/code&gt; is to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;make&lt;/strong&gt; &lt;code&gt;InitialDeck&lt;/code&gt; of cards&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;shuffle&lt;/strong&gt; it before each game&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;deal&lt;/strong&gt; from the &lt;code&gt;ShuffledDeck&lt;/code&gt; until&lt;/li&gt;
&lt;li&gt;we get &lt;code&gt;EmptyDeck&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The only addition to our code that seems to be needed is&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;sealed&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Deck&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InitialDeck&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Deck&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;SortedSet&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;InitialDeck&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@Nonnull&lt;/span&gt; &lt;span class="nc"&gt;SortedSet&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ShuffledDeck&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Deck&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;ShuffledDeck&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@Nonnull&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmptyDeck&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Deck&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;InitialDeck&lt;/span&gt; &lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// produce all combinations of Face and Suit - all cards&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;ShuffledDeck&lt;/span&gt; &lt;span class="nf"&gt;shuffle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InitialDeck&lt;/span&gt; &lt;span class="n"&gt;deck&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// pick your favourite shuffling algorithm&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Deck&lt;/span&gt; &lt;span class="nf"&gt;deal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ShuffledDeck&lt;/span&gt; &lt;span class="n"&gt;deck&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Consumer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// deal until you can't&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Good. Now we can think of &lt;code&gt;InitialDeck&lt;/code&gt;, &lt;code&gt;ShuffledDeck&lt;/code&gt; and &lt;code&gt;EmptyDeck&lt;/code&gt; as nodes in state machine while &lt;strong&gt;make&lt;/strong&gt;, &lt;strong&gt;shuffle&lt;/strong&gt; and &lt;strong&gt;deal&lt;/strong&gt; as transition between the nodes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F59au77s3oqnqdvdufqkk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F59au77s3oqnqdvdufqkk.png" alt="Deck state machine"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we have enforced all requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;there is only one way to create &lt;code&gt;InitialDeck&lt;/code&gt; - through smart constructor &lt;strong&gt;make&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;you can create &lt;code&gt;ShuffledDeck&lt;/code&gt; only if you have &lt;code&gt;InitialDeck&lt;/code&gt; beforehand&lt;/li&gt;
&lt;li&gt;you can &lt;strong&gt;deal&lt;/strong&gt; only from &lt;code&gt;ShuffledDeck&lt;/code&gt; - dealing from &lt;code&gt;EmptyDeck&lt;/code&gt; or &lt;code&gt;InitialDeck&lt;/code&gt; would be mistake&lt;/li&gt;
&lt;li&gt;you can empty a &lt;code&gt;Deck&lt;/code&gt; only if you &lt;strong&gt;deal&lt;/strong&gt; all it's cards&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;We saw how using product and sum types we can represent domain knowledge that will further be enforced and illegal states will not be possible. Also if we employ once again the idea of &lt;em&gt;smart constructors&lt;/em&gt; we can produce small state machines correctly describe workflow in the domain.&lt;/p&gt;

&lt;p&gt;The idea of type algebra and cardinality is quite powerful and we only scratched the surface with this article. If you are hungry for more you can check out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://justinpombrio.net/2021/03/11/algebra-and-data-types.html" rel="noopener noreferrer"&gt;Algebra and Data Types&lt;/a&gt; - awesome article that dives deeper and as final result encodes invariants of red-black tree into a type. How cool is that?&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://web.archive.org/web/20140222124650/http://chris-taylor.github.io/blog/2013/02/10/the-algebra-of-algebraic-data-types/" rel="noopener noreferrer"&gt;The Algebra of Algebraic Data Types&lt;/a&gt; 3 part series that goes as far as differentiating types&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>algebra</category>
      <category>datatype</category>
      <category>designpatterns</category>
    </item>
    <item>
      <title>Designing with Opaque types</title>
      <dc:creator>Nicola Todorov</dc:creator>
      <pubDate>Thu, 03 Jul 2025 20:35:46 +0000</pubDate>
      <link>https://dev.to/todoniko/opaque-types-439h</link>
      <guid>https://dev.to/todoniko/opaque-types-439h</guid>
      <description>&lt;h2&gt;
  
  
  Previously in Designing with types for the working programmer
&lt;/h2&gt;

&lt;p&gt;We have imbued meaning in &lt;code&gt;Email&lt;/code&gt; type&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Email&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But are all possible &lt;code&gt;String&lt;/code&gt; values a valid email address?&lt;br&gt;
Can we enforce validation so that we do not end up with &lt;em&gt;defensive programming&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;Sure. Constructor can enforce it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Email&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;Email&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="nc"&gt;Pattern&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="s"&gt;"^(.+)@(\\S+)$"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;matcher&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; 
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Not a valid email"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Are we really going to throw exceptions like it is new year?&lt;/p&gt;

&lt;p&gt;I summon &lt;em&gt;smart constructor&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Email&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;Email&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Email&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Pattern&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="s"&gt;"^(.+)@(\\S+)$"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;matcher&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Email&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;empty&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the constructor is &lt;code&gt;private&lt;/code&gt;. The only way to get valid &lt;code&gt;Email&lt;/code&gt; is to go through &lt;code&gt;parse&lt;/code&gt; - the &lt;em&gt;smart constructor&lt;/em&gt;. &lt;br&gt;
As a consequence the instance of &lt;code&gt;Email&lt;/code&gt; is like a boarding pass. It is a &lt;em&gt;proof&lt;/em&gt; in itself that the email is valid format. Correct by construction.&lt;br&gt;
This is what they call &lt;em&gt;opaque types&lt;/em&gt; and they ...&lt;/p&gt;
&lt;h2&gt;
  
  
  Make illegal states unrepresentable
&lt;/h2&gt;

&lt;p&gt;This phrase was coined by Yaron Minsky and captures a bit more than we are going experience in this article. Nevertheless opaque types are maybe the simplest incarnation of this idea.&lt;br&gt;
Look!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Password&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;Password&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;passowrd&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Password&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;empty&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Password&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now encode/enforce domain rules like&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Password&lt;/code&gt; has to be at least 7 chars long&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PositiveAmount&lt;/code&gt; guarantees non-negative values&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DiscountPercentage&lt;/code&gt; is within predefined range (0, 10]&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just think about it. With smart constructors we can now encode domain events into our types like &lt;code&gt;VerifiedUser&lt;/code&gt; - guarantee identity is confirmed.&lt;/p&gt;

&lt;p&gt;In each case the type itself is a proof that something was done.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Wrapper type + Smart constructor = Opaque type&lt;br&gt;
Simple as that.&lt;/p&gt;

&lt;p&gt;We traded extra lines of code for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;correctness by construction - illegal states can not be created&lt;/li&gt;
&lt;li&gt;business rules encoded in types - guaranteed by the compiler&lt;/li&gt;
&lt;li&gt;values with meaning - values communicate intent and what has been done already&lt;/li&gt;
&lt;li&gt;no defensive coding - validation as earliest as possible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are hungry for more and do not mind some Haskell, you can go ahead and read &lt;a href="https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/" rel="noopener noreferrer"&gt;Parse, don’t validate&lt;/a&gt;.&lt;br&gt;
For other resources you can google around for "Make illegal states unrepresentable" or better yet watch the original &lt;a href="https://www.youtube.com/watch?v=DM2hEBwEWPc" rel="noopener noreferrer"&gt;Effective ML by Yaron Minsky&lt;/a&gt;&lt;/p&gt;

</description>
      <category>datatype</category>
      <category>designpatterns</category>
      <category>smartconstructor</category>
    </item>
    <item>
      <title>Designing with Wrapper types</title>
      <dc:creator>Nicola Todorov</dc:creator>
      <pubDate>Thu, 03 Jul 2025 16:06:12 +0000</pubDate>
      <link>https://dev.to/todoniko/wrapper-types-4hao</link>
      <guid>https://dev.to/todoniko/wrapper-types-4hao</guid>
      <description>&lt;h2&gt;
  
  
  It compiles. It runs. So what's wrong?
&lt;/h2&gt;

&lt;p&gt;Let's start with a puzzle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;resetPassword&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Logic for sending reset password email&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What is the problem with this method?&lt;br&gt;

  Answer
  &lt;br&gt;
It might be used like so&lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;resetPassword&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPassword&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;/p&gt;

&lt;p&gt;You might be thinking I've gone off the rails for claiming there is problem in piece of code that has no logic in it, but there is a bug waiting. &lt;br&gt;
If you've spotted the problem you sure know that it will be very embarrassing if you need to fix such a bug.&lt;/p&gt;

&lt;p&gt;Let's have another.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What is wrong this time?&lt;/p&gt;

&lt;p&gt;
  Answer
  &lt;br&gt;
When instantiating, arguments can be swapped around.&lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"todoniko"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Sofia, Bulgaria"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"drama@mail.com"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;/p&gt;

&lt;p&gt;It compiles. It runs. No warnings. No type errors. But the potential for bug is there.&lt;/p&gt;

&lt;p&gt;Actually it is a whole class of bugs that the compiler could prevent - but doesn't, because we never told it how.&lt;/p&gt;

&lt;h2&gt;
  
  
  Addressing the root cause
&lt;/h2&gt;

&lt;p&gt;As with many things in programming we have jargon for this - it is a &lt;em&gt;code smell&lt;/em&gt; it is &lt;em&gt;primitive obsession&lt;/em&gt;.&lt;br&gt;
We can &lt;em&gt;encode&lt;/em&gt; way too many things with a &lt;code&gt;String&lt;/code&gt; - password, username, email, file path etc. But all those instances &lt;em&gt;mean&lt;/em&gt; different things and &lt;em&gt;communicate&lt;/em&gt; distinct purpose. In our heads we infer the meaning from the names and expose the encoding for everyone to (ab)use. We have failed at abstraction.&lt;/p&gt;

&lt;p&gt;Let's remedy that by wrapping/hiding the encoding/primitive type and expose only the meaning.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Email&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;UserName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Address&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserName&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Email&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Address&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;resetPassword&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Email&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Logic for sending reset email&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What have we achieved?
&lt;/h3&gt;

&lt;p&gt;Now the potential for bugs from passing the wrong argument has come down significantly. When our types are clear, bugs become rare.&lt;br&gt;
Now our types communicate &lt;em&gt;meaning&lt;/em&gt; instead of &lt;em&gt;encoding&lt;/em&gt; and this is  equally useful for both humans and AI agents.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The problem and solution in this article are not novel in any way. Actually they are too old to keep pretending that they do not exist.&lt;/p&gt;

&lt;p&gt;I have drawn inspiration from several sources and if you are daring enough to step out of the mainstream languages we use today you can have a look at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://fsharpforfunandprofit.com/posts/designing-with-types-single-case-dus/" rel="noopener noreferrer"&gt;Designing with types: Single case union types&lt;/a&gt; (F#)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://kowainik.github.io/posts/haskell-mini-patterns#newtype" rel="noopener noreferrer"&gt;Haskell mini-patterns handbook&lt;/a&gt; (Haskell)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://sporto.github.io/elm-patterns/basic/type-blindness.html" rel="noopener noreferrer"&gt;Type blindness&lt;/a&gt; (Elm)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please, don't be primitive.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is next
&lt;/h2&gt;

&lt;p&gt;In the next article we will upgrade our wrapper type so that we are not going to care if it needs validation. If it exists it is valid. The instance of the type will be the only &lt;em&gt;evidence&lt;/em&gt; we need. We will achieve correctness-by-construction with opaque types.&lt;/p&gt;

</description>
      <category>datatype</category>
      <category>designpatterns</category>
    </item>
    <item>
      <title>Lamenting about data types</title>
      <dc:creator>Nicola Todorov</dc:creator>
      <pubDate>Thu, 03 Jul 2025 04:46:23 +0000</pubDate>
      <link>https://dev.to/todoniko/lamenting-about-data-types-4ohn</link>
      <guid>https://dev.to/todoniko/lamenting-about-data-types-4ohn</guid>
      <description>&lt;h2&gt;
  
  
  Why most code is more fragile than it should be?
&lt;/h2&gt;

&lt;p&gt;Somewhere, right now, a developer is staring at a failing test or investigating production issue. It will take some time to figure it out. Maybe it was a string or a number passed into the wrong place.&lt;br&gt;
The compiler didn't complain. Neither did the tests - until someone fed it a value they weren't supposed to.&lt;br&gt;
The fix? A few extra &lt;code&gt;if&lt;/code&gt; statements. &lt;em&gt;Maybe&lt;/em&gt; a test added after the fact.&lt;br&gt;
The underlying cause? Never questioned.&lt;/p&gt;

&lt;p&gt;What if I told you ... that bug did not need to exist?&lt;br&gt;
What if your code could make that mistake impossible?&lt;br&gt;
Not caught, not detected, &lt;strong&gt;unrepresentable&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I am not talking about science fiction or some weird academic programming language. It's what type systems of Java or C# are already capable of doing - if you let them. Yet most developers treat types like seat belts - annoying at best, restrictive at worst.&lt;/p&gt;

&lt;h2&gt;
  
  
  Types vs Tests
&lt;/h2&gt;

&lt;p&gt;You've probably heard someone say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;That is why we write tests&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Fair enough. Yet let's compare:&lt;br&gt;
A test compares a handful of paths. &lt;br&gt;
A type covers them all.&lt;br&gt;
A test can be skipped or deleted. &lt;br&gt;
A type can't be ignored. (Don't worry &lt;em&gt;TypeScript&lt;/em&gt; we love you the way you are)&lt;br&gt;
A test catches problems after you've executed them. &lt;br&gt;
A type prevents you from writing them in first place.&lt;/p&gt;

&lt;p&gt;Types are not just for the compiler. They're for you, your teammates, and even your AI agent. They encode knowledge. They reflect rules. They act as living documentation that is always up to date, always enforced and always helpful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why isn't everyone doing this?
&lt;/h2&gt;

&lt;p&gt;And this is what keeps me up at night:&lt;br&gt;
We already have the tools. Mainstream languages have type systems that are capable enough. Modern IDEs are fantastic at navigating types. AI coding tools fair better when types guide them.&lt;/p&gt;

&lt;p&gt;Yet most teams still passing raw strings around like they're free candy. Still relying on test to catch what the compiler could have prevented. Still debugging issues that shouldn't have been representable in first place.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Because we humans are inherently sloppy.&lt;br&gt;
We were taught to "just get things working".&lt;br&gt;
We optimized for flexibility and speed - until our systems collapsed under the weight of ambiguity.&lt;br&gt;
We missed the essence:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A good type system doesn't slow you down. It keeps you from speeding into walls.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Plan of action
&lt;/h2&gt;

&lt;p&gt;Over the next few articles, I'll be introducing patterns for type creation that amplify the design process. I will stick to what Java or C# can encode, nothing fancy like dependent types or encoding fizzbuzz in the type system. My aim is practical and applicable.&lt;/p&gt;

&lt;p&gt;It is time to stop treating types like red tape. Designing with types won't make you invincible but it will make your code resilient, expressive and correct. Let's start thinking in types.&lt;/p&gt;

</description>
      <category>datatype</category>
      <category>designpatterns</category>
    </item>
  </channel>
</rss>
