<?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: Max Heiber</title>
    <description>The latest articles on DEV Community by Max Heiber (@maxheiber).</description>
    <link>https://dev.to/maxheiber</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%2F351577%2F1fa1f49b-6326-4394-909b-d720cfbca06c.jpg</url>
      <title>DEV Community: Max Heiber</title>
      <link>https://dev.to/maxheiber</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/maxheiber"/>
    <language>en</language>
    <item>
      <title>Function Intersection Types Considered Surprising</title>
      <dc:creator>Max Heiber</dc:creator>
      <pubDate>Sat, 23 Jan 2021 19:39:29 +0000</pubDate>
      <link>https://dev.to/maxheiber/function-intersection-types-considered-surprising-2805</link>
      <guid>https://dev.to/maxheiber/function-intersection-types-considered-surprising-2805</guid>
      <description>&lt;p&gt;Function intersection types sound simple, but get less intuitive the deeper one looks.&lt;/p&gt;

&lt;p&gt;Each of the following surprised me, and has its own section in this post:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When "or" means "intersection"&lt;/li&gt;
&lt;li&gt;Applying an Intersection&lt;/li&gt;
&lt;li&gt;What Erlang Does&lt;/li&gt;
&lt;li&gt;What TypeScript Does&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're short on time, skip to the last section, since what TypeScript does is most interesting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;amp;&lt;/code&gt; is &lt;a href="https://www.typescriptlang.org/docs/handbook/2/objects.html#intersection-types"&gt;intersection&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;|&lt;/code&gt; is &lt;a href="https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#union-types"&gt;union&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;x: T&lt;/code&gt; is a variable &lt;code&gt;x&lt;/code&gt; of type &lt;code&gt;T&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;'a1'&lt;/code&gt; in a type means a &lt;a href="https://www.typescriptlang.org/docs/handbook/literal-types.html#string-literal-types"&gt;singleton type&lt;/a&gt; inhabited by only the value &lt;code&gt;'a1'&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When "or" means "intersection"
&lt;/h2&gt;

&lt;p&gt;Here's an Erlang function that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;given an &lt;code&gt;'a1'&lt;/code&gt; returns &lt;code&gt;'r1'&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;given an &lt;code&gt;'a2'&lt;/code&gt; returns &lt;code&gt;'r2'&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Mnemonic: "a" for "argument", "r" for "return"&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;'a1'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;'r1'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;'a2'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;'r2'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;.&lt;/p&gt;

&lt;p&gt;We can give it a type specification like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="ni"&gt;spec&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;'a1'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;'r1'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;'a2'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;'r2'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;'a1'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;'r1'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;'a2'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;'r2'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you ask someone whether &lt;code&gt;;&lt;/code&gt; means "union" or "intersection" here, they are very likely to say "union." I made this mistake, too. There seems to be "or" reasoning going on: either the first function cluase is used, or the second is used.&lt;/p&gt;

&lt;p&gt;But here are some reasons for thinking the function is &lt;em&gt;not&lt;/em&gt; a union: in general, one cannot use a union of T and U in a way that takes advantage of its T-ness without first proving that it is a T. Here's a TypeScript example, if I have a variable &lt;code&gt;x&lt;/code&gt; of type &lt;code&gt;number | string[]&lt;/code&gt;, I can't do much with it until I figure out what it is. I have to do something like &lt;code&gt;if (Array.isArray(x)) { /* now I can treat x as an array }&lt;/code&gt;. If I have a &lt;code&gt;y&lt;/code&gt; of  type &lt;code&gt;number[] | string[]&lt;/code&gt; I can safely use &lt;code&gt;y.concat&lt;/code&gt; because that doesn't take advantage of &lt;code&gt;y&lt;/code&gt;'s &lt;code&gt;number[]&lt;/code&gt;-ness or &lt;code&gt;string[]&lt;/code&gt;-ness, it uses a method that's defined for both branches of the union.&lt;/p&gt;

&lt;p&gt;So &lt;code&gt;func&lt;/code&gt; is an intersection, not a union, otherwise we wouldn't be able to call it on &lt;code&gt;a1&lt;/code&gt; without first proving that the function isn't defined on &lt;code&gt;a2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;See how intuitive this is? It gets better!&lt;/p&gt;

&lt;h2&gt;
  
  
  Applying an Intersection
&lt;/h2&gt;

&lt;p&gt;Ideally, a type checker will be able to figure out the type of an expression like &lt;code&gt;f(x)&lt;/code&gt; based on the type of &lt;code&gt;f&lt;/code&gt; and the type of &lt;code&gt;x&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The typical rule for this sort of thing is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x: T  and f: T -&amp;gt; U
-------
f(x): U
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is, "The type of &lt;code&gt;f(x)&lt;/code&gt; is the return type of &lt;code&gt;f&lt;/code&gt;, assuming &lt;code&gt;x&lt;/code&gt; has the same type as &lt;code&gt;f&lt;/code&gt;'s parameter."&lt;/p&gt;

&lt;p&gt;But the type of &lt;code&gt;func&lt;/code&gt; above is the intersection of &lt;code&gt;'a1' -&amp;gt; 'r1'&lt;/code&gt; and &lt;code&gt;'a2' -&amp;gt; 'r2'&lt;/code&gt;, which doesn't clearly tell us what to do when applying the function: it doesn't have the same shape as &lt;code&gt;T -&amp;gt; U&lt;/code&gt; in our function application rule.&lt;/p&gt;

&lt;p&gt;One can make an argument for massaging the type of &lt;code&gt;func&lt;/code&gt; into the slightly surprising:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;('a1' | 'b1') -&amp;gt; ('r1' &amp;amp; 'r2')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, more generally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;F1: A1 -&amp;gt; R1
F2: A2 -&amp;gt; R2
----------
(F1 &amp;amp; F2): (A1 | A2) -&amp;gt; (R1 &amp;amp; R2)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is: "The type of a function intersection is a function type from the union of the parameter types to the intersection of the return types"&lt;/p&gt;

&lt;p&gt;I'll show how the function intersection rule above is sensible, then show how it's not.&lt;/p&gt;

&lt;p&gt;Some theoretical reasons for liking this rule are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For any types &lt;code&gt;T&lt;/code&gt; and &lt;code&gt;U&lt;/code&gt;, both &lt;code&gt;T&lt;/code&gt; and &lt;code&gt;U&lt;/code&gt; should be subtypes of &lt;code&gt;T &amp;amp; U&lt;/code&gt;. Then rule above is the only one that fits. This explanation is all you need if variance is super-intuitive to you and you remember that &lt;a href="https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)#Function_types"&gt;functions are contravariant in their inputs and covariant in their outputs&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Think of a function as like a burrito maker. Suppose my birthday is coming up and I ask you for a machine that accepts &lt;code&gt;flour&lt;/code&gt; and turns it into &lt;code&gt;burritos&lt;/code&gt;. And you give me a machine that can turn either &lt;code&gt;flour&lt;/code&gt; &lt;strong&gt;or&lt;/strong&gt; &lt;code&gt;corn&lt;/code&gt; into things that are &lt;strong&gt;both&lt;/strong&gt; &lt;code&gt;burritos&lt;/code&gt; and &lt;code&gt;delicious&lt;/code&gt;. Then I get what I wanted for my birthday, a strained metaphor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To make things more concrete, the signature does the right thing for examples like the following.  Given a spec:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="ni"&gt;spec&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
      &lt;span class="p"&gt;;(&lt;/span&gt;&lt;span class="n"&gt;'b'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the rule allows the following example implementation of function &lt;code&gt;f&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, I hope something still seems fishy.&lt;/p&gt;

&lt;p&gt;Intersecting the return types is weird!! What was the point of having the left side of the intersection in the spec say the function could return &lt;code&gt;1&lt;/code&gt; if it can't actually return &lt;code&gt;1&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;Put differently, the rule for how to intersect function types makes one wonder why one would bother writing specs with functions intersections at all. By the rule above, the spec for &lt;code&gt;f&lt;/code&gt; has the same meaning as this much simpler spec:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="ni"&gt;spec&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;'a'&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;'b'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rule for function intersections also seems to say the wrong thing about cases like our original example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="ni"&gt;spec&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;'a1'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;'r1'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;'a2'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;'r2'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;'a1'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;'r1'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;'a2'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;'r2'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function intersection rule says that the function above is &lt;code&gt;('a1' | 'a2') -&amp;gt; ('r1' &amp;amp; 'r2')&lt;/code&gt;. But what on Earth is an &lt;code&gt;'r1' &amp;amp; 'r2'&lt;/code&gt;? Neither Erlang nor TypeScript has any values of type &lt;code&gt;'r1' &amp;amp; 'r2'&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Perhaps the spec for &lt;code&gt;func&lt;/code&gt; doesn't need massaging into &lt;code&gt;T -&amp;gt; U&lt;/code&gt; form. Instead, we can tweak the function application rule, splitting it into two:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Rule 1

f: (A1 -&amp;gt; R1) &amp;amp; (A2 -&amp;gt; R2)
x: A1
-------------
f(x): R1

Rule 2

f: (A1 -&amp;gt; R1) &amp;amp; (A2 -&amp;gt; R2)
x: A2
-------------
f(x): R2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is, in order to calculate the return type of a function F applied to argument x, use the branch of the intersection with a parameter that matches the type of &lt;code&gt;x&lt;/code&gt;. Put more verbosely:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if the type of &lt;code&gt;x&lt;/code&gt; matches the parameter type of the &lt;em&gt;left&lt;/em&gt; side of the function intersection, the return type of the function application is the return type of the &lt;em&gt;left&lt;/em&gt; side of the function intersection&lt;/li&gt;
&lt;li&gt;if the type of &lt;code&gt;x&lt;/code&gt; matches the parameter type of the &lt;em&gt;right&lt;/em&gt; side of the function intersection, the return type of the function application is the return type of the &lt;em&gt;right&lt;/em&gt; side of the function intersection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a bit annoying in the implementation of the type checker, but a deeper problem is that we haven't yet said what to do when &lt;em&gt;both&lt;/em&gt; of our new function application rules match. What happens when &lt;code&gt;A1&lt;/code&gt; and &lt;code&gt;A2&lt;/code&gt; overlap? I'll say more about this in the next section.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Erlang Does
&lt;/h2&gt;

&lt;p&gt;The de-facto type-checker-like tool for Erlang is Dialyzer. Erlang has very clear runtime semantics for functions with multiple heads like &lt;code&gt;func&lt;/code&gt; and &lt;code&gt;f&lt;/code&gt; above: go through them one by one, using the first function head that matches. But it turns out that Dialyzer doesn't care about the order of function types in an intersection type!&lt;/p&gt;

&lt;p&gt;Nor does Dialyzer take the other option we discussed above of unioning the parameter types and intersecting the return types. Dialyzer does something closer to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;F1: A1 -&amp;gt; R1
F2: A2 -&amp;gt; R2
---------------
(F1 &amp;amp; F2): (A1 &amp;amp; A2) -&amp;gt; (R1 &amp;amp; R2)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might wonder why Dialyzer takes the &lt;em&gt;intersection&lt;/em&gt; of the parameter types rather than the union. There's a long answer I don't have space for here, but part of the story is that Dialyzer is more of a bug-finder (or discrepancy analyzer) than a type checker, so its rules are intentionally unsound.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This description is misleading, &lt;a href="https://dev.to/maxheiber/comment/1an4k"&gt;see Update 2&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What TypeScript Does
&lt;/h2&gt;

&lt;p&gt;Here is our original example, translated to TypeScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;r1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                   &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;r2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// type of `x` is 'r1'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// type of `y` is 'r2'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.typescriptlang.org/play?ssl=2&amp;amp;ssc=1&amp;amp;pln=3&amp;amp;pc=1#code/CYUwxgNghgTiAEYD2A7AzgF3gMwK4rAC554AKU2Ac2IHIoBGGgSngF4A+eGmRpgKBKChw4QDIyFGNS5QATMzadu8-n2TosADzY58YUnV7wA9MfgYAngAcESbPAAGmh-ACWaLjxprUmeBZ08AgMGBVNza1t7BwsXd095PiA"&gt;playground link&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;TypeScript function intersections are handled like in our &lt;code&gt;Rule 1&lt;/code&gt; and &lt;code&gt;Rule 2&lt;/code&gt;: when applying a function intersection to &lt;code&gt;x&lt;/code&gt;, pick the branch of the intersection with a parameter that matches the type of &lt;code&gt;x&lt;/code&gt;. That's how TS is able to assign different types to &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The interesting bit is that TypeScript designers had to make a choice about what happens when the parameter types of &lt;code&gt;F1&lt;/code&gt; and &lt;code&gt;F2&lt;/code&gt; overlap. Options include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Try Rule 1 and Rule 2 &lt;strong&gt;in order&lt;/strong&gt;, applying the first rule that matches&lt;/li&gt;
&lt;li&gt;OR reject outright attempts to intersect functions with overlapping domains&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first option sounds OK at first, but it has the &lt;em&gt;really&lt;/em&gt; surprising consequence that &lt;code&gt;A &amp;amp; B&lt;/code&gt; is not equivalent to &lt;code&gt;B &amp;amp; A&lt;/code&gt;. These are noncommutative intersections!&lt;/p&gt;

&lt;p&gt;The second option sounds great, but would not be practical for TypeScript. That's because TypeScript can't generally tell, for a given &lt;code&gt;x: T&lt;/code&gt; and &lt;code&gt;y: U&lt;/code&gt; whether or not the &lt;code&gt;x&lt;/code&gt; is also a &lt;code&gt;U&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;TypeScript makes a really interesting choice here. TS intersections both are and are not commutative! TypeScript plays fast and loose with equality, which is unsound (&lt;a href="https://github.com/microsoft/TypeScript/issues/42204"&gt;issue #42204&lt;/a&gt;), but seems to work OK in practice.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>erlang</category>
      <category>programming</category>
      <category>statictypes</category>
    </item>
    <item>
      <title>On Subtyping vs. Row Polymorphism, information loss, and actionable error messages</title>
      <dc:creator>Max Heiber</dc:creator>
      <pubDate>Fri, 11 Dec 2020 17:52:17 +0000</pubDate>
      <link>https://dev.to/maxheiber/subtyping-loses-information-row-polymorphism-does-not-2mb9</link>
      <guid>https://dev.to/maxheiber/subtyping-loses-information-row-polymorphism-does-not-2mb9</guid>
      <description>&lt;p&gt;Brian McKenna's &lt;a href="https://brianmckenna.org/blog/row_polymorphism_isnt_subtyping#:~:text=So%20now%20to%20answer%20the,there%20is%20no%20subtyping%20relationship"&gt;"Row Polymorphism Isn't Subtyping"&lt;/a&gt; is about the distinction between row polymorphism and subtyping. Several re-readings led me to convince myself I understood, then a real-world bug to lead me to a stronger conclusion on why the distinction matters.&lt;/p&gt;

&lt;p&gt;To help cement my understanding or misunderstanding, I'll&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;say more about &lt;em&gt;how&lt;/em&gt; row polymorphism isn't subtyping.&lt;/li&gt;
&lt;li&gt;share an example of how the information loss from subtyping can lead to hard-to-diagnose bugs&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Good background easy reads: &lt;a href="https://www.typescriptlang.org/docs/handbook/type-compatibility.html"&gt;TypeScript's subtyping&lt;/a&gt; and &lt;a href="https://elm-lang.org/docs/records#record-types"&gt;Elm's extensible records&lt;/a&gt; (row polymorphism lite).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How exactly Row Polymorphism is not Subtyping
&lt;/h2&gt;

&lt;p&gt;If I interpret McKenna correctly, he's saying that all and only type systems with subtyping have the subsumption rule, which says that if T1 is a subtype of T2 and e is a T1 then e is also a T2:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Subsumption Rule


e has type T1 and T1 subtype of T2
---------therefore
e has type T2

or, using more symbols:

e: T1 and T1 &amp;lt;: T2
--------
e: T2

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: Technically, I think it's a rule schema and not a rule, but I'll be sloppy&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It took me some time to see how row polymorphism isn't just the &lt;code&gt;&amp;lt;:&lt;/code&gt; in this rule.&lt;/p&gt;

&lt;p&gt;I'll follow Elm and use &lt;code&gt;{rowvar | a: Int, b: String}&lt;/code&gt; to mean "a record with at least fields &lt;code&gt;a: Int&lt;/code&gt; and &lt;code&gt;b: String&lt;/code&gt;. &lt;code&gt;rowvar&lt;/code&gt; is the row variable: it stands for the other fields in the record in addition to &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;. More generally: &lt;code&gt;{rowvar | k1: F1, ... kn: Fn}&lt;/code&gt; means "Record with at least fields k1 of type F1, k2 of type F2, etc."&lt;/p&gt;

&lt;p&gt;It seems we can define &lt;code&gt;&amp;lt;:&lt;/code&gt; (subtype of) in terms of row variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;when T1 is {rho1 | k1: F1, ... kn: Fn, ln: Gn ...}
and  T2 is {rho2 | k1: F1, ... kn: Fn}

then T1 &amp;lt;: T2  (T1 is a subtype of T2)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But then the subsumption rule &lt;em&gt;still&lt;/em&gt; doesn't follow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Subsumption Rule

e: T1 and T1 &amp;lt;: T2
----------------
e: T2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The extra work the subsumption rule is doing over rules for row polymorphism (which I did not write down) is that the subsumption rule allows an expression to have more than one type: e1 is both a T1 &lt;em&gt;and&lt;/em&gt; a T2.  What makes this interesting is that information is lost: when we see that something is a T2, we don't know whether it is also a T1.&lt;/p&gt;

&lt;p&gt;But with row polymorphism, the row variables maintain the information that would be lost with subtyping. What I did above in defining &lt;code&gt;&amp;lt;:&lt;/code&gt; in terms of row polymorphism sneakily ditched the row variable, which had the information about the other fields. Here's what happens if we don't sneak, and try to write something similar to the subsumption rule directly using row variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;e1: T1
T1 is {rho1 | e1: F1, ... en: Fn, ep: Fp}
T2 is {rho2 | e1: F1, ... en: Fn}
rho2 is (rho1 | ep: Fp)
---------------------
e1: T2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The made-up syntax in the last premise is meant to say that &lt;code&gt;rho2&lt;/code&gt; has all the same fields (with the same types) as rho1 and additionally has field &lt;code&gt;ep&lt;/code&gt; of type &lt;code&gt;Fp&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The above rule is useless because the conclusion is the same as the first premise: &lt;code&gt;e1&lt;/code&gt; has only one type since &lt;code&gt;T1&lt;/code&gt; and &lt;code&gt;T2&lt;/code&gt; are the same type. The type is just written differently in the second and third premises. When I wrote &lt;code&gt;T1&lt;/code&gt;, I listed field &lt;code&gt;ep&lt;/code&gt; explicitly, but when I wrote &lt;code&gt;T2&lt;/code&gt;, field &lt;code&gt;ep&lt;/code&gt; was included in the row variable &lt;code&gt;rho2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;All this is to say that if one squints at the subsumption rule one might convince oneself it applies to row polymorphism, but one would be incorrect.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that the information loss with subtyping can be optional. In popular languages with subtyping, the information can be retained but requires more keyboarding. Here is a TS example of essentially treating subtyping like it's row polymorphism: &lt;code&gt;function foo&amp;lt;A extends B&amp;gt;(a: A): A&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Perils of Information Loss
&lt;/h2&gt;

&lt;p&gt;The information loss caused by the subsumption rule does not play well with type inference. Which doesn't worry me much, since &lt;a href="https://dl.acm.org/doi/abs/10.1145/2577080.2577098"&gt;type signatures are useful documentation&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;A real-world bug I saw illustrates what I take to be a deeper issue with the information loss:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Animal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;tasty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Cow&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Animal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;moo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getFromBarn&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Animal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Cow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;tasty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;moo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mooooo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;cow&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Cow&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;moo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getFromBarn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cow&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Error! Expected Cow but got Animal&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgAgIImAWzgG2QbwChkTkw4BnMATwC4yoBXCAbkIF9DDRJZEUAwgHsA7sggAPSCAAmFNBmx4ipZJiFD6VKKADmbTlxiMQCMMCEhkuiGABiUIZgBCcKCAAUASnrosuAmJSBEsqZBCRemExAF5A1VVyKjoGZgAaIIS1DXoAInUNDVyM1XY2VShbRndw0QMjEzMLKwoABwg4AGsPCKjRH2QANyFgGXjg0KEcCAA6HCFdHtEZgq8OBtNzSzU4UG9xkhCQMIjkOJt7Rxc3Ty9y0jaO7oi71QB6N+QAUShHKABCb4SdpmCBjaLIABGjDA1iEsL8SnWQA"&gt;Try the code&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note: I sacrificed realism in trimming down the example&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What makes this bug interesting to me is that the type checker complains, &lt;em&gt;even though&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All the type annotations are correct&lt;/li&gt;
&lt;li&gt;The code is correct&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This stinks! There are several related issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As an advocate of static type checking, I think we should be rewarded for writing type annotations. But there is little payoff in this case, only more work.&lt;/li&gt;
&lt;li&gt;To n00b eyes, the error message is confusing: the function expects a cow and we gave it a cow. And cows are animals, but it's complaining.&lt;/li&gt;
&lt;li&gt;Even to expert eyes, it's not clear how to fix the code. Should we change the &lt;code&gt;getFromBarn()&lt;/code&gt;, &lt;code&gt;main()&lt;/code&gt;, or &lt;code&gt;speak()&lt;/code&gt;? It depends on the intent of the authors of each of these three functions, and how we want the codebase to evolve.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I don't know of an easy way out of the information loss problem with subtyping. Some routes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In this particular case, a really advanced compiler could point out the information loss in &lt;code&gt;getFromBarn()&lt;/code&gt; and say that just changing the annotation will make the problem go away, if the dev is sure that's what they want. But this won't be feasible in general.&lt;/li&gt;
&lt;li&gt;Tweak the subsumption rule so that information loss is opt-in only: users must explicitly say they are upcasting a &lt;code&gt;Cow&lt;/code&gt; to an &lt;code&gt;Animal&lt;/code&gt;. Which adds yet more work for the user.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One answer I don't think is right is "Use row polymorphism instead" as the techniques are not directly comparable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Subtyping is more general than just records, it is also useful for working with, for example, &lt;a href="https://www.typescriptlang.org/docs/handbook/literal-types.html"&gt;literal types&lt;/a&gt; and union types.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The information loss with subtyping can sometimes be desirable in order to hide implementation details so we can evolve our APIs: for example, exposing something as an &lt;code&gt;Iterable&lt;/code&gt; so we can switch from &lt;code&gt;Set&lt;/code&gt; to &lt;code&gt;Array&lt;/code&gt; in future. Maybe that's what the author of &lt;code&gt;getFromBarn()&lt;/code&gt; had in mind.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>programming</category>
      <category>polymorphism</category>
      <category>programminglanguages</category>
    </item>
    <item>
      <title>The Principle of Explosion in Ordinary Computer Programs</title>
      <dc:creator>Max Heiber</dc:creator>
      <pubDate>Sat, 05 Dec 2020 15:55:11 +0000</pubDate>
      <link>https://dev.to/maxheiber/the-principle-of-explosion-in-ordinary-computer-programs-111d</link>
      <guid>https://dev.to/maxheiber/the-principle-of-explosion-in-ordinary-computer-programs-111d</guid>
      <description>&lt;p&gt;There's normally a tight connection between programming and proving: this is known as "Propositions as Types." I found one aspect of the correspondence troubling, went down a rabbit hole, and came back less troubled. &lt;/p&gt;

&lt;p&gt;Our most popular logical systems all include &lt;strong&gt;exfalso&lt;/strong&gt;, a.k.a. The Principle of Explosion which is the principle that a contradiction implies anything at all. That is, &lt;code&gt;forall B, if false then B.&lt;/code&gt;Which seems really surprising on the face of it: where did &lt;code&gt;B&lt;/code&gt; come from?! I'll share my exploration of this question and an attempt at an answer.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Warning: There's nothing practical in this post.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Exfalso is easily derived in classical logic, the logic we're taught in school if we learn any logic at all. In classical logic, &lt;code&gt;A -&amp;gt; B&lt;/code&gt; means &lt;code&gt;(not A) or B&lt;/code&gt;. In classical logic, this is true by definition because &lt;code&gt;if false then B&lt;/code&gt; means &lt;code&gt;(not false) or B&lt;/code&gt;, which is just &lt;code&gt;true&lt;/code&gt; regardless of what &lt;code&gt;B&lt;/code&gt; is.&lt;/p&gt;

&lt;p&gt;What was unclear to me was where exfalso comes from in the logic that corresponds to computation* (intuitionistic logic). It's almost a secret that exfalso is &lt;em&gt;assumed&lt;/em&gt; in intuitionistic logic, without proof. But both intuitionists and our programming languages seem to quietly believe exfalso:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// exfalso in TypeScript is a function&lt;/span&gt;
&lt;span class="c1"&gt;// from a contradiction to anything at all&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;exfalso&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;contradiction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;contradiction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;*Note: I'm exaggerating a bit in calling intuitionistic logic the logic of computation. It's closest to how most of our programming languages seem to work most of the time. See &lt;a href="https://en.wikipedia.org/wiki/Linear_logic#The_resource_interpretation"&gt;Linear Logic: The resource interpretation&lt;/a&gt; and &lt;a href="https://www.cl.cam.ac.uk/~tgg22/publications/popl90.pdf"&gt;"A Formulae-as-Types Notion of Control&lt;/a&gt; for aspects of computation that other logics model better._&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Background on Intuitionistic Logic and Programming
&lt;/h2&gt;

&lt;p&gt;From a programmer's point of view, classical logic works for booleans, but otherwise rarely has much to do with our craft. That's because classical logic &lt;em&gt;assumes&lt;/em&gt; something we cannot compute: the law of excluded middle (or an equivalent axiom), which is &lt;code&gt;forall A, A or not A&lt;/code&gt; (each thing we can say is either true or false).&lt;/p&gt;

&lt;p&gt;To show why assuming the Law of Excluded Middle doesn't accurately describe computation, consider this TypeScript function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;thing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Thing&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The type signature says that this function will return either a number &lt;strong&gt;OR&lt;/strong&gt; a string. But at runtime there is no such thing as an instance of &lt;code&gt;number | string&lt;/code&gt; that is not specifically a number or a string. In both programming and intuitionistic logic, in order to construct an instance of "number or string" we must have a number or have a string.&lt;/p&gt;

&lt;p&gt;The correspondence with computation makes intuitionistic logic really attractive (at least to me), and this logic underlies some of our most cutting-edge programming languages (Coq, &lt;a href="https://plfa.github.io"&gt;Agda&lt;/a&gt;, Idris). &lt;/p&gt;

&lt;p&gt;Next I'll share where exfalso comes from in intuitionistic logic, the relationship to programming, and why everything is probably OK.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exfalso in Intuitionistic Logic and Programming
&lt;/h2&gt;

&lt;p&gt;If intuitionistic logic is the logic of what is programmable, then it's pretty strange that it says that in certain situations we can get any value we like for free (exfalso).&lt;/p&gt;

&lt;p&gt;It wasn't obvious to me from &lt;a href="https://en.wikipedia.org/wiki/Principle_of_explosion"&gt;Wikipedia&lt;/a&gt; or &lt;a href="https://plato.stanford.edu/entries/logic-intuitionistic/"&gt;The Stanford Encyclopedia of Philosophy&lt;/a&gt;, but exfalso is &lt;em&gt;assumed&lt;/em&gt; by intuitionistic logic. This is in contrast to classical logic, where exfalso is derivable. So it seems intuitionists (who assume very little) intentionally committed to this surprising principle.&lt;/p&gt;

&lt;p&gt;To try to figure out why, I looked at what early intuitionists had to say about exfalso. Note that intuitionism came before computers, so the inventors of intuitionism did not think about it as the logic of computation, but had similar interpretations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The logic where one judges what is constructable (Brouwer)&lt;/li&gt;
&lt;li&gt;  The logic where one finds a method of fulfilling/realizing an intention (Heyting)&lt;/li&gt;
&lt;li&gt;  The logic where one finds a method of solving a task (Kolmogorov)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Source: "Intuitionistic Type Theory" (Martin-Löf, 1980)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Brouwer basically said nothing about exfalso, but relied on it implicitly.&lt;/p&gt;

&lt;p&gt;Heyting subtly qualified his view of implication to include the commitment to exfalso, selling this qualification as "adding precision":&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As a matter of fact [exfalso] adds to the precision of the definition of implication. You remember that P → Q can be asserted if and only if we possess a construction which, joined to the construction of P would prove Q. Now suppose that ⊢ ¬P, that is, we have deduced a contradiction from the supposition that that P were carried out. Then, in a sense, this can be considered as a construction, which, joined to a proof of P (which cannot exist) leads to a proof of Q. I shall interpret then implication in this wider sense. (from "Intuitionism, an Introduction", Heyting)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Kolmogorov, to my ears at least, is clearer on the topic of exfalso:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As far as [exfalso] is concerned, as soon as [not A] is solved, the solution of A is impossible, and the problem of "A -&amp;gt; B" has no content. ... the proof that a problem is without content will always be considered as its solution.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Kolmogorov is &lt;em&gt;not&lt;/em&gt; saying that a contradiction implies anything. Instead, he's saying that we can safely pretend it does. Morally, this feels like a significant difference to me: exfalso is imagination run wild, but saying we don't have any particular obligations in impossible situations sounds reasonable. However, in formal systems as well as programming, I have a tough time seeing what the difference would be between pretending exfalso and believing exfalso.&lt;/p&gt;

&lt;p&gt;Take the following TypeScript example, noting that in programming contradiction can be thought of as unreachable code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;false&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;// unreachable&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out the &lt;code&gt;default&lt;/code&gt; case. If &lt;code&gt;bool&lt;/code&gt; is of type &lt;code&gt;boolean&lt;/code&gt;, why does TS let us treat it as having type &lt;code&gt;string&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;To see what's going on, try putting your mouse over &lt;code&gt;bool&lt;/code&gt; in the last return statement &lt;a href="https://www.typescriptlang.org/play?#code/GYVwdgxgLglg9mABAUwB4EMC2AHANsgCgCM45cAuREs5dMASkoGcoAnGMAc0QG8AoRIMRMA7jCgQAFomKlc9XgKHKI6JskTB0udeSXKDiVsighWSAERadyCwG59B1esRsQyPYcPHT5xBbdbBy9EABNkLRBcKE8QoQB6eMRwY3QpdCJ8RxCfMyRqXGChAF8+UqA"&gt;in the TypeScript playground&lt;/a&gt;. TypeScript reports that &lt;code&gt;bool&lt;/code&gt; is of type &lt;code&gt;never&lt;/code&gt; on that line. &lt;code&gt;never&lt;/code&gt; is TypeScript's name for "contradiction." Even though booleans are not numbers, you can return &lt;code&gt;bool&lt;/code&gt; in the &lt;code&gt;default&lt;/code&gt; case because the type checker knows that the &lt;code&gt;default&lt;/code&gt; case is unreachable.&lt;/p&gt;

&lt;p&gt;To me, the choice made by TS and other programming languages here helps clarify intuitionistic logic. It's not like when a contradiction is reached a genie appears, ready to grant any wish. Instead, we have no particular obligation with regard to our return types in unreachable parts of our programs. I think this gibes with what Kolmogorov was talking about when he said "the problem has no content" in cases of contradiction. "unreachable code" ~= "problem with no content."&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Heyting and Kolmogorov quotes and interpretation of them are from van Dalen's "Kolmogorov and Brouwer on constructive implication and the Ex Falso Rule"&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>programming</category>
    </item>
    <item>
      <title>What Makes a DSL Bad? Make, CSS, and how we can do better.</title>
      <dc:creator>Max Heiber</dc:creator>
      <pubDate>Sat, 28 Nov 2020 16:29:40 +0000</pubDate>
      <link>https://dev.to/maxheiber/what-makes-a-dsl-bad-make-css-and-how-we-can-do-better-10ji</link>
      <guid>https://dev.to/maxheiber/what-makes-a-dsl-bad-make-css-and-how-we-can-do-better-10ji</guid>
      <description>&lt;p&gt;There are many places where you can find arguments that DSLs (domain-specific languages) or "language oriented programming" are good. But I haven't found much on what makes them bad.&lt;/p&gt;

&lt;p&gt;My experiences with DSLs tend to be negative. There are cases where I know exactly what I want the computer to do. I could write it in minutes in any "real" programming language, but struggle to express or approximate it in the DSL.&lt;/p&gt;

&lt;p&gt;Here are some examples of "bad" DSLs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make&lt;/li&gt;
&lt;li&gt;CSS&lt;/li&gt;
&lt;li&gt;GitHub Actions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And here are sufficient conditions for a DSL to be bad:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Missing proper functions. By which I mean high school math functions: things that compute by turning variables into return values.&lt;/li&gt;
&lt;li&gt;Missing proper variables. By which I mean a scoped way of naming values.&lt;/li&gt;
&lt;li&gt;Mandatory. Regexes within a normal programming language are fine most of the time because we're not forced to use them: when things get too hard to express we can switch to writing a normal function with the full power of the programming language.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Honorable mention for a feature missing from bad DSLs: structured data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;On &lt;strong&gt;Make&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;The Makefile DSL is mandatory for Make. You can't find out that you need a variable and function and then just do it. You have to trick Make with environment variables, or stitching together shell scripts, storing state on the file system, more and more complicated funny symbols, etc. etc. Here's an example where I needed variables and functions recently: our 'test' rule depended on our 'build' rule, but we had more than one way of building. We wanted to run the same tests for each of these different ways of building. I managed to hack around this: having the makefile re-invoke &lt;em&gt;itself&lt;/em&gt; with an environment variable, then using that environment variable as a macro together with Makefile ternary conditional syntax. That's just silly!&lt;/p&gt;

&lt;p&gt;On &lt;strong&gt;CSS&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;In a stylesheet, CSS is mandatory: you can't nip out and write code in a real language, unless you count &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Houdini"&gt;Houdini&lt;/a&gt;. CSS doesn't have variables and functions. Which is why in typical hand-written CSS, one repeats oneself a lot, with "magic strings" for widths, fonts, etc. The only methods of composition are to repeat yourself or rely on the cascade, which has all of the flavor of shared mutable state, such as action at a distance/no way to reason locally.&lt;/p&gt;

&lt;p&gt;To see what CSS would look like if it had proper variables and functions, see &lt;a href="https://reactnative.dev/docs/style"&gt;how React Native does it&lt;/a&gt;: styles are just data, and can be assigned to variables, passed to functions, returned from functions, imported, distributed via package managers, etc.&lt;/p&gt;

&lt;p&gt;There may be good &lt;a href="https://blog.cloudflare.com/the-languages-which-almost-became-css/"&gt;performance reasons&lt;/a&gt; for not always executing a full-fledged programming language at runtime to style webpages. But then maybe instead of a limited language, there shouldn't be &lt;em&gt;any&lt;/em&gt; language at all for styles: just data that is generated by ahead-of-time compilers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If there's a perf argument for not having functions and variables in CSS, surely we can apply the same reasoning to CSS rule resolution. Rule resolution is &lt;a href="https://blog.cloudflare.com/html-parsing-2/"&gt;hard work&lt;/a&gt;, maybe it's a bad idea for us to make browsers do it at runtime.&lt;/li&gt;
&lt;li&gt;Most PLs without variables are doomed to eventually grow butchered variables. In CSS' case, it has at least two: &lt;a href="https://www.w3.org/TR/css-variables-1/"&gt;custom properties&lt;/a&gt;   and &lt;a href="https://blog.logrocket.com/styling-numbered-lists-with-css-counters/"&gt;counters&lt;/a&gt;. The latter link goes to an entire article on how to number paragraphs with CSS. It's really an entire article showing you how to do the equivalent of this JavaScript: &lt;code&gt;paragraphs.forEach((paragraph, i) =&amp;gt; ....)&lt;/code&gt;.  (Note: the article is great, CSS is the target of my cricisism).&lt;/li&gt;
&lt;li&gt;Even with all the power to crash the browser with &lt;a href="https://sudonull.com/post/7589-CraSSh-breaking-all-modern-browsers-with-CSS-calculations"&gt;&lt;code&gt;var&lt;/code&gt; and &lt;code&gt;calc&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://jsfiddle.net/Camilo/eQyBa/"&gt;accidental Turing-completeness&lt;/a&gt;, ad-hockery (media query syntax, counters, &lt;a href="https://css-tricks.com/lets-not-forget-about-container-queries/"&gt;more to come&lt;/a&gt;) it turns out people still want to style the browser using languages that have variables and functions (see SASS and CSS-in-JS). &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On &lt;strong&gt;GitHub Actions&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://docs.github.com/en/free-pro-team@latest/actions"&gt;GitHub workflows&lt;/a&gt;, one very often has repeated names for things (such as an artifact one wants to generate and upload). One must copy and paste and then hope things are in sync. Or suppose one wants to do similar, but slightly different, things on pushing to a branch and on making a release. Copy/paste again, this time making several small tweaks to different steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do Bad DSLs happen to Good people?
&lt;/h2&gt;

&lt;p&gt;If it's so awful working with these DSLs, then how and why did we get into this situation? The answer is a little different in each of these cases:&lt;/p&gt;

&lt;p&gt;Why the &lt;strong&gt;Make language&lt;/strong&gt; exists&lt;/p&gt;

&lt;p&gt;I suspect Make has a DSL because high-level composable scripting languages weren't such a thing then. And if there were, it would be non-obvious how to mix the genuinely declarative aspects of Make with the "do this and then do that" nature of idiomatic Python. &lt;a href="https://avdi.codes/rake-part-1-basics/"&gt;Rake&lt;/a&gt; seems to strike a nice balance here, though I haven't used it much. It's the mandatoriness that's the problem with Make, not the fundamental model.&lt;/p&gt;

&lt;p&gt;Why &lt;strong&gt;CSS&lt;/strong&gt; exists:&lt;/p&gt;

&lt;p&gt;CSS: People are so used to CSS that it's hard to imagine alternatives, preprocessors aside. &lt;a href="https://blog.cloudflare.com/the-languages-which-almost-became-css/"&gt;"The Languages which Almost Became CSS"&lt;/a&gt; gives some idea of constraints and alternatives. It was mainly for performance reasons that we didn't get a "real" programming language. That's fine, but it tells me that CSS makes more sense as a data format or bytecode than something for humans. See "What about SQL" below for more on what I mean here.&lt;/p&gt;

&lt;p&gt;Why the &lt;strong&gt;GitHub Actions&lt;/strong&gt; language exists:&lt;/p&gt;

&lt;p&gt;GitHub actions are broken for no technical reason I can discern. They didn't butcher the language for performance reasons: You can write an infinite loop in a workflow with a "run" step with some Bash &lt;code&gt;while true; do echo hello; done&lt;/code&gt;. You can waste memory and CPU all you want: GH will charge you for what you use, once you've exceeded the limits of the free tier. It's not for security reasons: Everything is sandboxed anyway, and is already side-effecty.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about SQL?
&lt;/h2&gt;

&lt;p&gt;SQL is pretty good in practice, but meets my definition of a "bad" DSL. The reason SQL doesn't seem totally broken is that it is typically &lt;strong&gt;generated&lt;/strong&gt;, not hand-written. SQL is stitched together by code in real programming languages. For example, programmers of general-purpose languages write functions that generate and execute prepared statements. Parameters of functions in the general purpose language to bind parameters to the prepared statement. Or people use query builders or ORMs.&lt;/p&gt;

&lt;p&gt;SQL could be better, of course, and I'm not just talking about all the syntactic inconsistencies. As a compile target, ideally it would be better-suited to being generated. Rethnkdb and MongoDB (in spite of its other faults) both get this right, treating queries more as data than as code in some butchered language without proper variables and functions, making query-building more composable and &lt;a href="https://www.explainxkcd.com/wiki/index.php/327:_Exploits_of_a_Mom"&gt;safe&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the rare cases where apps &lt;em&gt;are&lt;/em&gt; written in SQL, it's not really SQL, it's SQL+, where one has variables and functions: see the stored procedure languages for Postgres and SQL Server, which are particularly like real languages.&lt;/p&gt;

&lt;h2&gt;
  
  
  How can we do better?
&lt;/h2&gt;

&lt;p&gt;Here are some alternatives to bad DSLs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What's so bad about a real programming language with proper variables and functions? If your reasons are that you want something easy to learn and safe to embed, consider something like &lt;strong&gt;Lua&lt;/strong&gt;. Lua seems to work well for &lt;a href="https://redis.io/commands/eval"&gt;Redis stored procedures&lt;/a&gt;, the video game industry (see Roblox for an example), &lt;a href="https://blog.cloudflare.com/pushing-nginx-to-its-limit-with-lua/"&gt;Nginx config&lt;/a&gt;, etc. &lt;a href="https://www.gnu.org/software/guile/"&gt;Guile&lt;/a&gt; is a similar option for audiences parentheses-sympathetic.&lt;/li&gt;
&lt;li&gt;Would plain data meet your needs?

&lt;ul&gt;
&lt;li&gt;Consider making it easy for app devs to write "real" code that generates the data, rather than providing them with a broken language that is somewhere between data and code.

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://eslint.org/docs/user-guide/configuring#configuration-file-formats"&gt;eslint&lt;/a&gt; and &lt;a href="https://webpack.js.org/configuration/"&gt;webpack&lt;/a&gt; both enable users to write their config in either JSON or JS code that generates JSON-like objects. This has some of the benfits of a DSL, while enabling abstraction when it is needed.&lt;/li&gt;
&lt;li&gt;If one wants static guarantees about the data generated by code, one can go a lot further in &lt;a href="https://research.fb.com/publications/holistic-configuration-management-at-facebook/"&gt;refining the code-that-generates-data approach&lt;/a&gt; (disclosure: I currently work at the company behind that paper, opinions are my own).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;If there are strong reasons to control side-effects and enforce limited modes of indirection, consider &lt;a href="https://docs.dhall-lang.org/tutorials/Language-Tour.html"&gt;Dhall&lt;/a&gt;, if your audience is ML-syntax-sympathetic&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;As soon as you find yourself reinventing variables, loops, and functions with your "plain data" &lt;strong&gt;STOP&lt;/strong&gt; &lt;strong&gt;STOP&lt;/strong&gt; and consider one of the alternatives above. It isn't plain data anymore, it's a bad programming language.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;May our tools be &lt;a href="https://www.youtube.com/watch?v=rTRzYjoZhIY"&gt;bicycles for the mind&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Update: I rewrote the section on CSS in response to feedback.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>programming</category>
      <category>devops</category>
      <category>css</category>
    </item>
    <item>
      <title>The Type of a `type` in Typescript</title>
      <dc:creator>Max Heiber</dc:creator>
      <pubDate>Mon, 16 Mar 2020 21:42:16 +0000</pubDate>
      <link>https://dev.to/maxheiber/the-type-of-a-type-in-typescript-171</link>
      <guid>https://dev.to/maxheiber/the-type-of-a-type-in-typescript-171</guid>
      <description>&lt;p&gt;I'll present four puzzles and two solutions about TypeScript &lt;code&gt;class&lt;/code&gt;es and &lt;code&gt;type&lt;/code&gt;s.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The cover image is from &lt;a href="https://medium.com/@jiwonjessicakim/russells-paradox-f8897"&gt;another article&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;These are just puzzles I find fun, but reading this might have the happy side effect of getting you out of a TS jam in the future. All four puzzles have come up in real-life situations that I've been asked about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Puzzle 1
&lt;/h2&gt;

&lt;p&gt;TypeScript has a neat feature, type-level &lt;code&gt;typeof&lt;/code&gt;. It's probably inspired by the distinct value-level JS feature also called &lt;code&gt;typeof&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;       &lt;span class="c1"&gt;// "object" &lt;/span&gt;
&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt; &lt;span class="c1"&gt;// "function"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;TypeScript's type-level &lt;code&gt;typeof thing&lt;/code&gt; gives you an alias for the type of the variable &lt;code&gt;thing&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;thing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;thing&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// OK&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But what is the type of &lt;code&gt;Num&lt;/code&gt;?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TypeType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;Num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// error: 'Num' only refers to a type, but is being used as a value here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;TypeScript won't even let us ask the question.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Coq, Agda, and Idris all let you ask this type of question, but it is un-askable in TypeScript.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So we've disovered this rule: in TS, types don't have types. Fair enough. So what's going on in the following example?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;AType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second line shows us that &lt;code&gt;A&lt;/code&gt; is a type (we are using it to say that &lt;code&gt;a&lt;/code&gt; is of type &lt;code&gt;A&lt;/code&gt;).&lt;br&gt;
Then the third line shows us that we can take the type of &lt;code&gt;A&lt;/code&gt;. So it looks like we've taken the type of a type!&lt;/p&gt;

&lt;p&gt;Puzzle 1 is: "How can types both &lt;em&gt;have&lt;/em&gt; and &lt;em&gt;not have&lt;/em&gt; types in TypeScript?&lt;/p&gt;
&lt;h2&gt;
  
  
  Puzzle 2
&lt;/h2&gt;

&lt;p&gt;Puzzle 2 is: How can &lt;code&gt;AA&lt;/code&gt; be both equal and not equal to &lt;code&gt;A&lt;/code&gt; below?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;AA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// if AA and A really are the same type,&lt;/span&gt;
&lt;span class="c1"&gt;// then we'd expect them to behave the same way&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;works&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="c1"&gt;// OK&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;doesNotWork&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;AA&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Error&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When reading the example above, bear in mind the principle of &lt;a href="https://en.wikipedia.org/wiki/Identity_of_indiscernibles"&gt;Identity of Indiscernables&lt;/a&gt;. If &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;AA&lt;/code&gt; really are equal, then we'd expect to be able to use &lt;code&gt;AA&lt;/code&gt; wherever we use &lt;code&gt;A&lt;/code&gt;. But the last two lines of the example show a case where &lt;code&gt;A&lt;/code&gt; is allowed but &lt;code&gt;AA&lt;/code&gt; is not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution to Puzzles 1 and 2
&lt;/h2&gt;

&lt;p&gt;At this point, there are two puzzles:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How could &lt;code&gt;AA&lt;/code&gt; be both equal and not equal to &lt;code&gt;A&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;How can types both &lt;em&gt;have&lt;/em&gt; and &lt;em&gt;not have&lt;/em&gt; types in TypeScript?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The puzzles are just illusions caused by the interaction of two TS features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TS has two worlds of things: the World of Values and the World of Types&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;class&lt;/code&gt; declarations introduce both a type and a value&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Things like &lt;code&gt;type&lt;/code&gt; aliases and &lt;code&gt;interface&lt;/code&gt;s live in the World of Types. Variables declared with &lt;code&gt;const&lt;/code&gt;, &lt;code&gt;let&lt;/code&gt; and &lt;code&gt;var&lt;/code&gt; exist in the World of Values. You're allowed to reuse names in the same scope as long as they refer to things in different worlds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Thing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Thing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// no error&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But two things in the same world cannot have the same spelling.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;thing2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;thing2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt; &lt;span class="c1"&gt;// error: Cannot re-declare block-scoped variable "thing2"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Ignore apparent violations of the rule for &lt;code&gt;interface&lt;/code&gt;, &lt;code&gt;namespace&lt;/code&gt;, and &lt;code&gt;enum&lt;/code&gt;. This is the dread &lt;a href="https://www.typescriptlang.org/docs/handbook/declaration-merging.html"&gt;"declaration merging"&lt;/a&gt; feature I &lt;a href="https://medium.com/@maxheiber/alternatives-to-typescript-enums-50e4c16600b1"&gt;wrote about earlier&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As you saw above, we can use &lt;code&gt;type&lt;/code&gt; to name something in the World of Types and &lt;code&gt;const&lt;/code&gt; to name something in the World of Values. But a &lt;code&gt;class&lt;/code&gt; declarations is magical: it &lt;em&gt;simultaneously&lt;/em&gt; names something in the world of values and names another thing in the world of types!&lt;/p&gt;

&lt;p&gt;The next example illustrates this double-declaration behavior. Note that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the type &lt;code&gt;C&lt;/code&gt; is the type of &lt;em&gt;instances&lt;/em&gt; of &lt;code&gt;C&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Applying the type world's &lt;code&gt;typeof&lt;/code&gt; operator to &lt;code&gt;C&lt;/code&gt; gives you the type of the value-land &lt;code&gt;C&lt;/code&gt;, which is a constructor function.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;C&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;CInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;// alias the `C` from the World of Types&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Constructor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// alias the `C` from the World of Values&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;C&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;c2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cons&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;C&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Constructor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// The next line errors, because CInstance does not have the same dual-nature as `C`&lt;/span&gt;
&lt;span class="c1"&gt;// CInstance is *only* a type, so you cannot calculate its type&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cons2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;CInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Constructor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two puzzles solved!&lt;/p&gt;

&lt;p&gt;Consider again an example like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;AA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// OK&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ZZ&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;AA&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Error&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Puzzle 1 was "How could &lt;code&gt;AA&lt;/code&gt; be both equal and not equal to &lt;code&gt;A&lt;/code&gt;?".&lt;/p&gt;

&lt;p&gt;The answer is that there are two &lt;code&gt;A&lt;/code&gt;s: one in the world of types and one in the world of values. &lt;code&gt;AA&lt;/code&gt; is equal to the &lt;code&gt;A&lt;/code&gt; in the world of types, but not equal to the &lt;code&gt;A&lt;/code&gt; in the world of values.&lt;/p&gt;

&lt;p&gt;Puzzle 2 was "How can types both &lt;em&gt;have&lt;/em&gt; and &lt;em&gt;not have&lt;/em&gt; types in TypeScript?"&lt;/p&gt;

&lt;p&gt;The answer is that we can never ask about the types of types in TypeScript. The seeming-violation of this rule was only because we were dealing with two &lt;code&gt;A&lt;/code&gt;s: a type-level &lt;code&gt;A&lt;/code&gt; and a value-level &lt;code&gt;A&lt;/code&gt;. We can ask for the &lt;code&gt;typeof&lt;/code&gt; the value-level A, but TS won't let us ask about the type of the type-level &lt;code&gt;A&lt;/code&gt; or of any of its aliases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Puzzle 3
&lt;/h2&gt;

&lt;p&gt;Puzzle 3 is: why are there no errors in the code example below?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Klass&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;konstructor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Klass&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Klass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;Klass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;konstructor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Klass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;konstructor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// why no error here?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Puzzle 4
&lt;/h2&gt;

&lt;p&gt;Puzzle 4 is: how can we correctly-type a function that returns a class?&lt;/p&gt;

&lt;p&gt;For example, is there a way to get things like this to compile?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createClass&lt;/span&gt;&lt;span class="p"&gt;({});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MyClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>typescript</category>
    </item>
  </channel>
</rss>
