<?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: Patrick Kelly</title>
    <description>The latest articles on DEV Community by Patrick Kelly (@entomy).</description>
    <link>https://dev.to/entomy</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%2F446201%2F304dba9e-ec51-4b8c-b01b-76f666ffb708.jpeg</url>
      <title>DEV Community: Patrick Kelly</title>
      <link>https://dev.to/entomy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/entomy"/>
    <language>en</language>
    <item>
      <title>C#'s Generic Math from F#</title>
      <dc:creator>Patrick Kelly</dc:creator>
      <pubDate>Mon, 12 Dec 2022 11:40:00 +0000</pubDate>
      <link>https://dev.to/entomy/cs-generic-math-from-f-31a7</link>
      <guid>https://dev.to/entomy/cs-generic-math-from-f-31a7</guid>
      <description>&lt;p&gt;At this rate I should just legally rename myself to the language bindings guy or something. Fourth year in a row and I've got more to talk about when it comes to .NET bindings. But hey, I'm &lt;a href="https://www.planetgeek.ch/2022/12/02/our-journey-to-f-c-f-interop/"&gt;not the only one&lt;/a&gt; this time! This year? The team introduced some goodies with .NET 7.0 and C# 11. &lt;a href="https://learn.microsoft.com/en-us/dotnet/standard/generics/math"&gt;Generic Math&lt;/a&gt; is one of particular interest for use from F#, because of how well it fits with how F# already works. Like everything Microsoft has developed however, it clearly was rushed and has some rough spots. We'll be exploring those, and how I've found for working around them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;I must really be milking this subject, right? You've read my last articles, you know how this is going to work. The generic math feature introduced with C# 11 and .NET 7.0 is just methods off generic interfaces. We can just call them directly like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="n"&gt;abs&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;:^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it! I don't need to write another article on this again. Try it though. It fails. Miserably. The syntax analyzer will recognize the problem: this just isn't valid F#.&lt;/p&gt;

&lt;p&gt;So what about this?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="n"&gt;abs&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;:^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;INumberBase&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="nc"&gt;Abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not invalid syntax anymore, but this still won't compile. So how do we actually call this then? The trick is in a simplified form of what we've already done before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;Abs&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;INumberBase&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="n"&gt;abs&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Extensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This actually solves another problem as well, or, at least what I consider a problem: numerical functions from the Generic Math API have poor discoverability the way they were implemented. If you don't want extension methods on the C# side, just remove the &lt;code&gt;this&lt;/code&gt; part; no other changes are necessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cranking to 11
&lt;/h2&gt;

&lt;p&gt;Okay, that was simple, just unexpected. Surely that's it, and I'm still just milking an article. Four years straight of this? Well... We're about to need to dive into the internals of the F# standard library and features that only exist inside of it. Yeah, this just went hard. The problem lies with a few of the Generic Math interfaces that are kinda already represented in F#, but not in the same way: operators. What do I mean? Let's look at how F# implements the operators:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="o"&gt;(+)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;V&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; 
    &lt;span class="nc"&gt;AdditionDynamic&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;(^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;),(^&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="o"&gt;),(^&lt;/span&gt;&lt;span class="nc"&gt;V&lt;/span&gt;&lt;span class="o"&gt;)&amp;gt;&lt;/span&gt;  &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; 
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;int32&lt;/span&gt;       &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;int32&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;int32&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;       &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;float32&lt;/span&gt;     &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;float32&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;float32&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;int64&lt;/span&gt;       &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;int64&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;int64&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint64&lt;/span&gt;      &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint64&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint64&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint32&lt;/span&gt;      &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint32&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint32&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;nativeint&lt;/span&gt;   &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;nativeint&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;nativeint&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;unativeint&lt;/span&gt;  &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;unativeint&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;unativeint&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;int16&lt;/span&gt;       &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;int16&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"conv.i2"&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;int32&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;int16&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint16&lt;/span&gt;      &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint16&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"conv.u2"&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint32&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint16&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;        &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"conv.u2"&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint32&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sbyte&lt;/span&gt;       &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sbyte&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"conv.i1"&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;int32&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sbyte&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;byte&lt;/span&gt;        &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;byte&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"conv.u1"&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint32&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;byte&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;      &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Concat&lt;/span&gt;&lt;span class="o"&gt;((#&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="o"&gt;#),(#&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="o"&gt;#)))&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt;     &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;op_Addition&lt;/span&gt;&lt;span class="o"&gt;((#&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt; &lt;span class="o"&gt;#),(#&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt; &lt;span class="o"&gt;#)))&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;V&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt;
    &lt;span class="c1"&gt;// According to the somewhat subtle rules of static optimizations,&lt;/span&gt;
    &lt;span class="c1"&gt;// this condition is used whenever ^T is resolved to a nominal type or witnesses are available&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;((^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="o"&gt;):&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="o"&gt;(+)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;V&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you've never seen &lt;code&gt;(# #)&lt;/code&gt; blocks in F# before, congratulations, we're about to learn about something you can never use in your own code! This is a special feature only usable within the F# standard library, allowing for inline "IL" to be written. Kinda. It's mostly IL but there's some conveniences. We can't use this, but it is useful to understand what is going on in this method, to see what we can or can't do about it. If we want to include the Generic Math operators, this behavior has to be reimplemented in entirety. So let's break this down.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="nc"&gt;AdditionDynamic&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;(^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;),(^&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="o"&gt;),(^&lt;/span&gt;&lt;span class="nc"&gt;V&lt;/span&gt;&lt;span class="o"&gt;)&amp;gt;&lt;/span&gt;  &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is clearly some internal from the standard library, so, what does that look like?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nc"&gt;AdditionDynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;type3eq&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;int32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="n"&gt;int32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="n"&gt;int32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;int32&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt; 
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;type3eq&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt; 
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;type3eq&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;float32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="n"&gt;float32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="n"&gt;float32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;float32&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt; 
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;type3eq&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="n"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="n"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;int64&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt; 
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;type3eq&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="n"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="n"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint64&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt; 
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;type3eq&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uint32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="n"&gt;uint32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="n"&gt;uint32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint32&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt; 
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;type3eq&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nativeint&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="n"&gt;nativeint&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="n"&gt;nativeint&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;nativeint&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt; 
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;type3eq&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unativeint&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="n"&gt;unativeint&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="n"&gt;unativeint&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;unativeint&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt; 
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;type3eq&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;int16&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"conv.i2"&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="n"&gt;int16&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="n"&gt;int16&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;int32&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;int16&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;type3eq&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uint16&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"conv.u2"&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="n"&gt;uint16&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="n"&gt;uint16&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint32&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint16&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;type3eq&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"conv.u2"&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint32&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;type3eq&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sbyte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"conv.i1"&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="n"&gt;sbyte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="n"&gt;sbyte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;int32&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sbyte&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;type3eq&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"conv.u1"&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="n"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="n"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint32&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;byte&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;type3eq&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;type3eq&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;op_Addition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="n"&gt;decimal&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;convPrim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt;&lt;span class="n"&gt;decimal&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nc"&gt;BinaryOpDynamicImplTable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OpAdditionInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="nc"&gt;Invoke&lt;/span&gt; &lt;span class="s2"&gt;"op_Addition"&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Oh dear god, this is a mess, and it's still not even the entire thing, because there's that &lt;code&gt;BinaryOpDynamicImplTable&amp;lt;OpAdditionInfo, 'T1, 'T2, 'U&amp;gt;&lt;/code&gt; type as well. However, we have everything we need to look at here, to see what behavior we need to provide. Going back to the &lt;code&gt;(+)&lt;/code&gt; definition, let's look at one of the lines.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;int32&lt;/span&gt;       &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;int32&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;int32&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This isn't too bad. When &lt;code&gt;^T&lt;/code&gt; and &lt;code&gt;^U&lt;/code&gt;, which are both input types, are both &lt;code&gt;int32&lt;/code&gt;, do &lt;code&gt;(# "add" x y : int32 #)&lt;/code&gt;; just a simple add instruction. There's many more lines like this that you can interpret the same way. So let's look at one with a bit more going on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;int16&lt;/span&gt;       &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;int16&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"conv.i2"&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;int32&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;int16&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You recognize the &lt;code&gt;(# "add" x y : int32 #)&lt;/code&gt; part from before. Critically here though, you'll recognize the &lt;code&gt;: int32&lt;/code&gt; portion clashes with the &lt;code&gt;int16&lt;/code&gt; type of the parameters. However, if you're used to C#, you might recognize this is correct behavior. .NET adds smaller numbers as 32-bit numbers. You have to convert back if you want smaller numbers again. &lt;code&gt;(# "conv.i2"&lt;/code&gt; is the instruction for converting the top of the stack to an &lt;code&gt;i2&lt;/code&gt;, or a two-byte integer; in F# you know this as a 16-bit integer, or &lt;code&gt;int16&lt;/code&gt;. And lastly &lt;code&gt;: int16 #)&lt;/code&gt; is just a typemark, which we now know matches the &lt;code&gt;i2&lt;/code&gt; part of &lt;code&gt;conv&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To summarize at this point, we've seen two behaviors. For numerics larger than 32-bits, they are added directly. For numerics smaller than 32-bits, they are upsized, added, and then converted back to their input size.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;      &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Concat&lt;/span&gt;&lt;span class="o"&gt;((#&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="o"&gt;#),(#&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="o"&gt;#)))&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's parts of this that I could explain but won't. The critical part is something you've probably already figured out: when the input is two strings, concatenate them. We see this behavior in C# as well, and it's exactly the same.&lt;/p&gt;

&lt;p&gt;This is now three different behaviors. Lovely.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt;     &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(#&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;op_Addition&lt;/span&gt;&lt;span class="o"&gt;((#&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt; &lt;span class="o"&gt;#),(#&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt; &lt;span class="o"&gt;#)))&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;V&lt;/span&gt; &lt;span class="o"&gt;#)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read this the same as the &lt;code&gt;string&lt;/code&gt; one, and you can see that given two &lt;code&gt;decimal&lt;/code&gt;, we're calling &lt;code&gt;Decimal.op_Addition&lt;/code&gt; on them. This is the internal name for the addition operator, however your language presents it.&lt;/p&gt;

&lt;p&gt;That leaves one last line in the main section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;((^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt;&lt;span class="o"&gt;):&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="o"&gt;(+)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;U&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nc"&gt;V&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And uhh... this is one I understand but don't understand, if you understand me. &lt;code&gt;(static member (+) : ^T * ^U -&amp;gt; ^V) (x,y))&lt;/code&gt; is something you've seen before if you've read my previous articles. We're calling &lt;code&gt;op_Addition&lt;/code&gt; on the parameters. &lt;code&gt;when ^T : ^T&lt;/code&gt; is the part I'm a little confused by. Not constraining &lt;code&gt;^T&lt;/code&gt; at all theoretically makes sense as a catch all, but considering I could never actually get this line of code to execute, I think they've made a mistake here. Regardless, the intention is for the standard &lt;code&gt;+&lt;/code&gt; operator to fallback to any defined &lt;code&gt;op_Addition&lt;/code&gt; that exists.&lt;/p&gt;

&lt;p&gt;So what about the next block, the &lt;code&gt;AdditionDynamic&lt;/code&gt; part? I'll let you read through that. It's another case where I understand but don't understand. It's basically a repeat of what we already covered, but is supposed to include behavior to automatically convert compatible types. If this sounds like something F# doesn't do, congratulations, you see why I'm confused.&lt;/p&gt;

&lt;p&gt;So why do I say F#'s fallback addition doesn't work? Well, the reference project I have for writing this has the following definitions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// &amp;lt;inheritdoc/&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Percent&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;operator&lt;/span&gt; &lt;span class="o"&gt;+(&lt;/span&gt;&lt;span class="nc"&gt;Percent&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Percent&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Value&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;/// &amp;lt;inheritdoc/&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="n"&gt;operator&lt;/span&gt; &lt;span class="o"&gt;+(&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Percent&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;right&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;left&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The thing is, the &lt;code&gt;^T percent -&amp;gt; ^T percent -&amp;gt; ^T percent&lt;/code&gt; one works fine, it's the &lt;code&gt;^T -&amp;gt; ^T percent -&amp;gt; ^T&lt;/code&gt; one that doesn't. Looking back at the &lt;code&gt;+&lt;/code&gt; definition, it should have caught this, so, what's going on here?&lt;/p&gt;

&lt;p&gt;Let's review what necessary behaviors we're after:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Numerics greater than the working size of .NET (32-bit) can be added together directly and their results returned.&lt;/li&gt;
&lt;li&gt;Numerics lesser than the working size of .NET (32-bit) must be converted to 32-bit numerics of compatible typeclass then added together, with their results converted back to the origin type.&lt;/li&gt;
&lt;li&gt;Strings are concatenated together.&lt;/li&gt;
&lt;li&gt;Any types with a defined &lt;code&gt;op_Addition&lt;/code&gt; should have that used.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Is there another way we can get all this behavior? Well, yeah, actually. Let's start with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;Adds two values together to compute their sum.&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="o"&gt;:^&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="o"&gt;:^&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="o"&gt;):^&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="o"&gt;((^&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;right&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;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="o"&gt;(+)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can probably tell, this is very similar to that catch-all line from the standard definition, although there's some differences. Funnily enough, this works in almost all of the cases we need it to. For 1, 3, and 4 of the requirements we laid out, this already works great. All of these tests will compile and pass fine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="nn"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Equal&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;1&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="nn"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Equal&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;0&lt;/span&gt;&lt;span class="p"&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;0&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nn"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"hello!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"hello"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;"!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nn"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;percent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's pretty awesome, because there's wayyyyy less code on our end.&lt;/p&gt;

&lt;p&gt;But what about requirement 2?&lt;/p&gt;

&lt;p&gt;I'll leave this one to you to fix, as practice makes perfect and there's a lot to digest in this article. My tip is that the solution is something we covered right here in this article, but there's another way to solve it that comes from a prior article. As it stands now, adding numerics smaller than 32-bits adds fine, but returns a 32-bit numeric, which is standard behavior for .NET itself, C#, and VB. All that needs to be done is that in these cases, the return value be converted back to the origin type. In the rest of the cases, we're already got correct behavior.&lt;/p&gt;

&lt;p&gt;If you've made it this far, the good news is that I've already done all the work in implementing both the &lt;a href="https://www.nuget.org/packages/Numbersome"&gt;base library&lt;/a&gt; and &lt;a href="https://www.nuget.org/packages/Numbersome.FSharp"&gt;F# bindings&lt;/a&gt; for this.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>fsharp</category>
    </item>
    <item>
      <title>Real World F# Interop</title>
      <dc:creator>Patrick Kelly</dc:creator>
      <pubDate>Sat, 25 Dec 2021 11:12:24 +0000</pubDate>
      <link>https://dev.to/entomy/real-world-f-interop-1nbe</link>
      <guid>https://dev.to/entomy/real-world-f-interop-1nbe</guid>
      <description>&lt;p&gt;For various reasons my past few years in development have involved a lot of language bindings, both reading up on others techniques and my own experimentation. I've written before about &lt;a href="https://dev.to/entomy/advanced-f-interop-5a57"&gt;writing advanced bindings&lt;/a&gt;, and &lt;a href="https://dev.to/entomy/designing-around-f-interop-2pnf"&gt;designing around bindings&lt;/a&gt;. However, these articles always used trivial examples. I've never talked before about the bindings I've written, why I used the techniques I did, and why I didn't use other approaches.&lt;/p&gt;

&lt;p&gt;Today, that changes.&lt;/p&gt;

&lt;p&gt;I have several libraries I maintain. For various reasons, several of these have been greatly simplified recently. The general idea is that each serves some domain, some with large amounts of custom methods and types, and others as simply large collections of extensions. Critically, some of these depend on another, and share method names. Because of this, use of a library that depends on another should extend the bindings. This can be a surprising challenge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Numbersome
&lt;/h2&gt;

&lt;p&gt;This is just a small convenience library meant to provide basic functionality more easily, and patch up some areas I needed to use often that weren't covered by larger math libraries. It also shows off something I couldn't until recently. Prior to this last .NET release (6.0) generic math was a problem to write, and was typically easier to write in F# and make C# bindings for instead. That's changed. Consider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;Crd&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IFloatingPoint&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;two&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;One&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;One&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;two&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="n"&gt;two&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;A simple Chord function. You don't see it much anymore, although it is useful at times, and often isn't used enough to remember one of the identities, so it's a suitable candidate. Luckily, this is easy, as we can write a very direct mapping.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="n"&gt;crd&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="p"&gt;:&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;IFloatingPoint&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;:^&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Crd&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is possible without more complex techniques precisely because there's only one method that this ever needs to bind to, and that method is sufficiently generic. The compiler doesn't need to be tricked; it just needs to be told what &lt;code&gt;^t&lt;/code&gt; is. An in doing so, this could be considered exactly identical to the C# signature. There's a method, a generic type constrained to a CRTP interface, a single parameter of that generic type, and a return of that type. If you have a single &lt;em&gt;generic&lt;/em&gt; method that needs to be bound to, this is the least effort. Easy enough.&lt;/p&gt;

&lt;p&gt;It won't be very obvious yet, but eventually it would become clear how operator overloading will become an issue. "Would" might have been overlooked, but I do mean past tense. There's numerous ways to address this, an in the past some of them were terrible. It's not that way anymore. Numbersome includes many definitions that work exactly like the standard F# operators and look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="o"&gt;:^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="o"&gt;:^&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;):^&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="o"&gt;((^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;c&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;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="n"&gt;op_Addition&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This winds up only being a slight bit of complexity over the aforementioned binding. What we're saying here can be broken up into several parts. &lt;code&gt;(^a or ^b or ^c)&lt;/code&gt; says the member constraint we're looking for can be found on any of the types: lefthand, righthand, or return. This forms a critical part of covering both preexisting types, and extending seamlessly to new types. &lt;code&gt;(static member op_Addition&lt;/code&gt; tells the compiler we're binding to a static member, which all operators are, called &lt;code&gt;op_Addition&lt;/code&gt;, which is the special name the compiled IL uses, that CLS Compliant languages understand as the &lt;code&gt;+&lt;/code&gt; operator. &lt;code&gt;^a -&amp;gt; ^b -&amp;gt; ^c&lt;/code&gt; is, of course, the signature of the operator. By using different type definitions we can potentially have unique types in different parameters, but, of course, can all be unified to the same type like the standard F# operators. This yields more flexibility than the standard F# definition, which, yay.&lt;/p&gt;

&lt;h2&gt;
  
  
  Collectathon
&lt;/h2&gt;

&lt;p&gt;Collectathon used to be a data structures library. Because of increasing demands on my personal life, I've decided to squash this down to the bare minimum required to get what I needed out of a good DS API. I've reworked things into a broad set of extension methods for the existing data structures. It's not quite the design I wanted, and imposes some trickier issues with method binding.&lt;/p&gt;

&lt;p&gt;Consider &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.memoryextensions.contains"&gt;&lt;code&gt;Contains()&lt;/code&gt;&lt;/a&gt; which exists only for &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.span-1"&gt;&lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.readonlyspan-1"&gt;&lt;code&gt;ReadOnlySpan&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/a&gt;. Arguments can definitely be made about &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.memory-1"&gt;&lt;code&gt;Memory&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/a&gt;, how it should be conceptualized, what it should support, but arrays? Really? No one thought to include a method to check arrays for a value? Sure, the loop isn't hard to write, except that more efficient checks which use partial loop unrolling or vectorization are actually non-trivial, and clutter code. Implementing this was simple enough:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;Boolean&lt;/span&gt; &lt;span class="n"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[]?&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IEquatable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;MemoryExtensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But now we have a slight problem. This, and others, are in a different static class as the ones for &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.span-1"&gt;&lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.readonlyspan-1"&gt;&lt;code&gt;ReadOnlySpan&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/a&gt;. I wrote before about binding to multiple overloads when they're all in a single static class, so I won't cover that again. But as for multiple? It's doable, but it's a closed extension.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="nc"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&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;^&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="o"&gt;(^&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;b&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;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="nc"&gt;Contains&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="o"&gt;)&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="o"&gt;((^&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;b&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;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="nc"&gt;Contains&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only thing that's different about the overloading part is the additional &lt;code&gt;^u&lt;/code&gt;. The function signature looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="n"&gt;contains&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;:^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;:^&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="nc"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CollectathonExtensions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MemoryExtensions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&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;^&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This winds up working better than F# side binder types in this scenario. As long as new extensions are added to either of the declared static types it will automatically be available on the F# side as well. A method of the same name and compatible signature in another static class in a scoped namespace? That works in C# but not F#. At least not with this technique. I am looking for an open extension mechanism here, but for now, only closed sets.&lt;/p&gt;

&lt;p&gt;Interestingly, this closed set technique does have quite a limitation when you take this further. Consider extending types in both &lt;code&gt;System.Collections.Generic&lt;/code&gt; and &lt;code&gt;System.Collections.Immutable&lt;/code&gt;. Say we add a &lt;code&gt;Requeue&lt;/code&gt; method for both respective &lt;code&gt;Queue&lt;/code&gt; types. This isn't an easy problem to solve, and one or the other will collide and cause problems. Of course, standard extension method calls are viable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stringier
&lt;/h2&gt;

&lt;p&gt;A lot of this library is, from a binding standpoint, conceptually identical to the methods in Collectathon, only it additionally binds to its own overloads as well. This just means an extra static class parameter in each of the bindings, so this doesn't need to be covered.&lt;/p&gt;

&lt;p&gt;However, those of you who know my work know this isn't all that needs to be addressed. And let me tell you, the work I've been doing on optimizations here caused some problems that weren't easy to address.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Pattern&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please do this. It's self explainatory, but it does make things more pleasant on the F# side where types are often lowercase.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Pattern&lt;/code&gt; has many predefined patterns, especially for UNICODE Categories or Contributory Properties. Luckily, these are also very straightforward.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;letter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Pattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Letter&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similarly, there's some factory functions defined there as well. These should not be mapped directly in my case, because of the overloading of textual types.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="n"&gt;blockComment&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;:^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="o"&gt;:^&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="nc"&gt;BlockComment&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Pattern&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&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;^&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="n"&gt;stop&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The overloading part looks exactly as you'd expect.&lt;/p&gt;

&lt;p&gt;Now, while there are techniques for overloading in F#, it's not as advanced as you might expect, and different parameter counts must have different functions for them. This creates the following two functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="n"&gt;fuzzy&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="o"&gt;:^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;):&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="nc"&gt;Fuzzy&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Pattern&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="n"&gt;fuzzy2&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxEdits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="o"&gt;:^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;):&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="nc"&gt;Fuzzy2&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Pattern&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt; &lt;span class="n"&gt;maxEdits&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I want to bring up an important detail here, that even if I've brought up before, I want to hammer home. What we would call the "caller" in OOP is a (typically) implicit first parameter. However, in FP this parameter should instead be the last parameter, because when using function piping, the piped values are placed last. &lt;code&gt;2&lt;/code&gt; as a suffix is a well understood convention, so downstream will generally understand it. Preferably however, use a clarifying suffix.&lt;/p&gt;

&lt;p&gt;Pattern construction is where things start to go south.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="n"&gt;many&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="o"&gt;:^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;):&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="nc"&gt;Many&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;StringierPatternsExtensions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The modifiers are straight forwards, since (now) all of them are extension methods. This actually has an incredibly nice effect in that, unless the pattern is a single literal, every single part will implicitly convert. So what about the single literals? &lt;code&gt;Pattern&lt;/code&gt; has constructors, but .NET doesn't like constraining on parameterized constructors. Well, F# doesn't care too much.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="n"&gt;ptn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="o"&gt;:^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;):&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="o"&gt;(^&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Pattern&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yup. You can use this pretty easily inside of functions that need more complex logic. Essentially, this &lt;em&gt;is&lt;/em&gt; the constructor, as long as it's only one parameter.&lt;/p&gt;

&lt;p&gt;I used to call this &lt;code&gt;p&lt;/code&gt;, taking after the FParsec &lt;code&gt;pchar&lt;/code&gt; and &lt;code&gt;pstring&lt;/code&gt; conventions, but I've decided more recently that's too vague. &lt;code&gt;ptn&lt;/code&gt; seems to strike a good ballance between succinct and clear.&lt;/p&gt;

&lt;p&gt;Now we get into problems. "Or", or alternates, is something a lot of parser engines struggle with how to create syntax for. FParsec went with &lt;code&gt;&amp;lt;|&amp;gt;&lt;/code&gt;, it's own operator. Most just assume you're going to use the C# API. You can use &lt;code&gt;||&lt;/code&gt; or &lt;code&gt;|||&lt;/code&gt; however, without creating issues, as long as you put it together with a few things we've covered earlier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="nc"&gt;Or&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;StringierPatternsExtensions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;NumbersomeExtensions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;_,&lt;/span&gt; &lt;span class="o"&gt;_,&lt;/span&gt; &lt;span class="o"&gt;_&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yeah, I hid something from you earlier 😜 We still have the closed extension problem from earlier, but we can add behavior to an operator. Just know that if anyone else does this you start to have collisions. I'm including both of these because it depends on the symbol you overload.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="nc"&gt;Or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="n"&gt;right&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;left&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="nc"&gt;Or&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;where&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;IBitwiseOperators&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows the F# operator to still behave as expected, while also allowing a familiar "or" operator for pattern construction. I suppose you'd call me antagonistic towards idiomatic F#, and I suppose you'd be correct.&lt;/p&gt;

&lt;p&gt;Now is where it all falls apart. Yeah. For many parts of this we're into undocumented and unintended abuse of language features to make this stuff work in extensible and low effort ways. But there be dragons.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;parse&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;:^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;byref&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="o"&gt;):^&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the signature I want. Unlike typical bindings, this is &lt;em&gt;almost&lt;/em&gt; idiomatic F#. If I were to wrap up &lt;code&gt;source&lt;/code&gt; and &lt;code&gt;location&lt;/code&gt; into a record or something, it could be entirely idiomatic F#. Since the signature is so different, you run into issues, but I really do want to make this work. What I do know, is that a technique I've never covered here is useful. Sometimes you might not want to bind to the public API, but rather, recompose internal APIs into the same effect. Enter: &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.internalsvisibletoattribute"&gt;&lt;code&gt;InternalsVisibleToAttribute&lt;/code&gt;&lt;/a&gt;. When this is applied, it allows other assemblies to still access internal members.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="n"&gt;parse&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;:^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;byref&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="o"&gt;):^&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Consume&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;Unchecked&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;defaultof&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;StringComparison&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This almost works. &lt;em&gt;Almost&lt;/em&gt;. F# wants to resolve &lt;code&gt;^a&lt;/code&gt; to &lt;code&gt;ReadOnlySpan&amp;lt;Char&amp;gt;&lt;/code&gt;. I &lt;em&gt;think&lt;/em&gt; I can write an overloader for &lt;code&gt;Consume&lt;/code&gt; and have this work, although the additional slicing has me unsure. If I manually declare &lt;code&gt;^a&lt;/code&gt; and &lt;code&gt;^b&lt;/code&gt; as &lt;code&gt;String&lt;/code&gt;, it does work.&lt;/p&gt;

&lt;p&gt;Alternatively, one of the F# side binder types may do the trick here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;I have, however, run out of time. I work 50 hours a week, and in school, and do this development on the side. As of yesterday (Dec 24th), this is as far as I've gotten in my own code.&lt;/p&gt;

&lt;p&gt;Last time I had as a footnote the possibility of Haskell style Variadic Functions. As far as I can tell this "feature" isn't possible anymore. That's probably a good thing 😂 But it would have been a fun tool in the toolbox.&lt;/p&gt;

&lt;p&gt;I do have a few things to track down. While playing with things, I think I found a mechanism by which it's possible to have a F# function overloaded on &lt;em&gt;both&lt;/em&gt; instance and static members. This would have huge implications for certain areas, like where some types have instance methods but others only extension methods for the same features.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>fsharp</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Pattern Combinators</title>
      <dc:creator>Patrick Kelly</dc:creator>
      <pubDate>Sun, 20 Dec 2020 15:14:21 +0000</pubDate>
      <link>https://dev.to/entomy/pattern-combinators-222g</link>
      <guid>https://dev.to/entomy/pattern-combinators-222g</guid>
      <description>&lt;p&gt;My conference talk on the theoretical model behind the parsing framework I developed.&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/oPHM6FEqDEI"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Designing Around F# Interop</title>
      <dc:creator>Patrick Kelly</dc:creator>
      <pubDate>Wed, 09 Dec 2020 13:36:01 +0000</pubDate>
      <link>https://dev.to/entomy/designing-around-f-interop-2pnf</link>
      <guid>https://dev.to/entomy/designing-around-f-interop-2pnf</guid>
      <description>&lt;p&gt;Last year I wrote about &lt;a href="https://dev.to/entomy/advanced-f-interop-5a57"&gt;Advanced F# Interop&lt;/a&gt; techniques. It was based on tackling the least ideal situation of language interop: A C# (or VB) library that was never designed with F# in mind. The techniques used were straight up abuse of the language, but were able to warp incredibly non-FP code into FP code.&lt;/p&gt;

&lt;p&gt;I still want to cover these points, but I don't want C# and VB programmers thinking it's acceptable to never consider interop. There's techniques which make it easier to design C# and VB libraries while &lt;em&gt;also&lt;/em&gt; making it easier to create the F# bindings. And yes, there's techniques for doing this the other way around as well, which I'll cover in time.&lt;/p&gt;

&lt;p&gt;For almost two years now I've been developing and maintaining a set of libraries where cross language compatibility is a hard design requirement. Obviously, I want this to be effective while not requiring a ton of effort. This article covers my findings, and integrated contributions of others towards that goal. The hope is that this will help library authors support the entire .NET ecosystem with a better overall feel, because we're better together.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Past
&lt;/h1&gt;

&lt;p&gt;A quick primer on what was done in the past, if you hadn't read my previous article. I'll be carving it up, simplifying it immensely by the end of this.&lt;/p&gt;

&lt;p&gt;I turned this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DoubleStack&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mutable&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Push&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Multiply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;into this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;stack&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="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;|=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mul&lt;/span&gt; &lt;span class="o"&gt;|=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sub&lt;/span&gt;
&lt;span class="nn"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;peek&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;mostly through this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;Pipeline&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="nc"&gt;Pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nc"&gt;DoubleStack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;left&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="nc"&gt;Pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DoubleStack&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="o"&gt;(^&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;a&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;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="nc"&gt;Pipe&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;DoubleStack&lt;/span&gt;&lt;span class="o"&gt;)&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="o"&gt;((^&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;a&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;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="nc"&gt;Pipe&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;DoubleStack&lt;/span&gt;&lt;span class="o"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="o"&gt;|=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="o"&gt;:^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Pipeline&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I don't want to go deep into explaining because we're going to remove much of this, but:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;|=&amp;gt;&lt;/code&gt; doesn't need to be an operator, I was just trying to be creative. Any F# function will work, and currying is recommended but not required. This tells the compiler it needs to resolve types at the callsite. &lt;code&gt;pipe&lt;/code&gt; is what sets up the binding. It looks for, and then calls, a static &lt;code&gt;Pipe()&lt;/code&gt; on either &lt;code&gt;^t&lt;/code&gt; or &lt;code&gt;^a&lt;/code&gt;. In &lt;code&gt;|=&amp;gt;&lt;/code&gt; we've said that &lt;code&gt;^t&lt;/code&gt; is &lt;code&gt;Pipeline&lt;/code&gt;, which is where &lt;code&gt;Pipe()&lt;/code&gt; is declared. You can't specify only &lt;code&gt;^t&lt;/code&gt;, as multiple type parameters are required to "confuse" the compiler.&lt;/p&gt;

&lt;p&gt;The end result is when the public function, &lt;code&gt;|=&amp;gt;&lt;/code&gt; in this case, is compiled, the compiler attempts to resolve a &lt;code&gt;Pipe()&lt;/code&gt; with a signature that matches the types at the callsite.&lt;/p&gt;

&lt;p&gt;In a normal C# binding situation &lt;code&gt;Pipe()&lt;/code&gt; would be calling C# methods, or &lt;code&gt;pipe&lt;/code&gt; would be a &lt;code&gt;member&lt;/code&gt; binding, not a &lt;code&gt;static member&lt;/code&gt; binding. But as I said, we're going to design around simplifying this entire thing.&lt;/p&gt;

&lt;h1&gt;
  
  
  Traits
&lt;/h1&gt;

&lt;p&gt;I've wrote previously on how &lt;a href="https://dev.to/entomy/real-traits-in-c-4fpk"&gt;C# does support traits&lt;/a&gt; and even added it as far back as C# 3.0. Borrowing a key definition from that article, we have:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Let's make sure we're all on the same page about what a trait is. This will also be useful in explaining why this approach works.&lt;br&gt;
A trait is a specific feature of a type. A method it supports. A property. Whatever. It's just saying: "I have this thing".&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;On the C# side this is actually a little less than idea. It's limiting in that unlike a first-class trait system, there's no way in C# to add traits to existing types. Extension methods allow for adding a method with the same name and signature as it would have if there was first-class traits, but this is less than ideal.&lt;/p&gt;

&lt;p&gt;F#'s functions have one of the more powerful and sophisticated generic constraint systems I've seen, only being bested by Ada. Because of this sophistication it's very easy to define trait-based functions in F#. In fact, you've certainly done this normally when writing F# functions, even without explicit constraints.&lt;/p&gt;

&lt;p&gt;So what we're left with is using a trait-pattern in C# allows for a high degree of consistency in name and signature, which F# bindings need. But also inconsistency in whether those methods are instance or static members. That's a problem.&lt;/p&gt;

&lt;h1&gt;
  
  
  Null tollerance
&lt;/h1&gt;

&lt;p&gt;Admittedly, I stumbled upon this completely unrelated to anything regarding F#, but quickly realized its application here as well. I try to avoid exceptions. They have their role, and I'll certainly use them before I start returning &lt;code&gt;Int32&lt;/code&gt; as an error code. But they are &lt;em&gt;heavy&lt;/em&gt;. &lt;code&gt;NullArgumentException&lt;/code&gt; and &lt;code&gt;NullDereferenceException&lt;/code&gt; are particularly annoying ones for many. I happened to have many instances where a well defined action could be taken if the caller was &lt;code&gt;null&lt;/code&gt;. But if instance methods always have an &lt;em&gt;implicit&lt;/em&gt; caller, how do we check if that's &lt;code&gt;null&lt;/code&gt;? This was always something that bugged me about C#, having also programmed extensively in Ada. Conceptually, I knew how to deal with this; I knew it shouldn't be anywhere near as big of a problem.&lt;/p&gt;

&lt;p&gt;I worked out how, and wrote about it &lt;a href="https://dev.to/entomy/avoiding-nulls-with-extension-methods-3mkc"&gt;here&lt;/a&gt;. If you haven't read that entire article, the short version is roughly: if you want to know how many items are in a bag, and you don't even have a bag, how many items do you have? You don't get a &lt;code&gt;NullDereferenceException&lt;/code&gt; irl, you have no items. So let's code for that by adding null-tollerance into extension methods, then calling the non-public instance methods. Cumbersome for many? Maybe. I figured it was most applicable for library authors, and only when well defined graceful action could be taken for a &lt;code&gt;null&lt;/code&gt; caller. But it had unintentional side effects.&lt;/p&gt;

&lt;p&gt;I could now provide default interface implementations and have them show up across &lt;em&gt;every&lt;/em&gt; type with that trait, callable like normal instance methods.&lt;/p&gt;

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

&lt;p&gt;&lt;em&gt;I just pushed all methods into static classes&lt;/em&gt;. F# functions had a fully consistent constraint to bind to.&lt;/p&gt;

&lt;h1&gt;
  
  
  Refined F# Bindings / Putting It All Together
&lt;/h1&gt;

&lt;p&gt;Unlike before, I'm lifting these examples &lt;em&gt;directly&lt;/em&gt; from the libraries I've mentioned, so you can see a real life applied case of this.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IAddable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TElement&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TElement&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;params&lt;/span&gt; &lt;span class="n"&gt;TElement&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;null&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="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TElement&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&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;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Memory&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TElement&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ReadOnlyMemory&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TElement&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TElement&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;ReadOnlySpan&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TElement&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ReadOnlySpan&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TElement&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TElement&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&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;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TEnumerator&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TEnumerator&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;TEnumerator&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IEnumerator&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TElement&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;null&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="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TElement&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here we have a straightforward but featureful "trait". All an implementer needs to provide is an implementation of &lt;code&gt;Add(TElement)&lt;/code&gt;, and they get the &lt;code&gt;{,ReadOnly}{Memory,Span}&amp;lt;TElement&amp;gt;&lt;/code&gt; and &lt;code&gt;IEnumerable&amp;lt;TElement, TEnumerator&amp;gt;&lt;/code&gt; variants for free. Why is &lt;code&gt;IEnumerable&amp;lt;&amp;gt;&lt;/code&gt; different? You can ignore that, it's a library specific thing; you want to use the one in &lt;code&gt;System.Collections.Generic&lt;/code&gt;. Like mentioned before, on its own this really isn't useful, since you need to call these off the interface, which forces a very particular style that is problematic with such "anemic" interfaces.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;partial&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TraitExtensions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TElement&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;IAddable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TElement&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TElement&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;null&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="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TElement&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;IAddable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TElement&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;params&lt;/span&gt; &lt;span class="n"&gt;TElement&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;null&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="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TElement&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;IAddable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TElement&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Memory&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TElement&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;null&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="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// And so on...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Whether &lt;code&gt;Add()&lt;/code&gt; should do nothing with a &lt;code&gt;null&lt;/code&gt; collection is debatable, of course. My thinking was similar to writing to &lt;code&gt;/dev/null&lt;/code&gt; versus an actual file.&lt;/p&gt;

&lt;p&gt;This is where four of the important things I had mentioned took place. We've now added graceful handling of &lt;code&gt;null&lt;/code&gt; callers. We've now allowed the default interface implementations to be called off the implementing type, not just the interface. We've greatly reduced the amount of code in &lt;em&gt;large&lt;/em&gt; code bases by providing single implementations of many things. And, if we need to add &lt;code&gt;And()&lt;/code&gt; or whatever other method to a preexisting type, we can do that inside of this static class and have everything consistent for the F# side of things.&lt;/p&gt;

&lt;p&gt;Lastly, the F# binding side is just this now:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="k"&gt;internal&lt;/span&gt; &lt;span class="nc"&gt;Bindings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="nc"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&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;^&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="o"&gt;(^&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;a&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;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="nc"&gt;Add&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&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;^&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt;&lt;span class="o"&gt;)&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;((^&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;a&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;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="nc"&gt;Add&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&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;^&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt;&lt;span class="o"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;

&lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AutoOpen&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;]&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Functions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="nc"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TraitExtensions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;_,&lt;/span&gt; &lt;span class="o"&gt;_&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt;
        &lt;span class="n"&gt;collection&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This works like before, but I'm going to summarize again for those unfamiliar with the previous approach, and to be extra clear about how this interacts with the newer design.&lt;/p&gt;

&lt;p&gt;You call &lt;code&gt;add&lt;/code&gt;, which, due to being &lt;code&gt;inline&lt;/code&gt; has its types resolved at the callsite. It, in turn, calls &lt;code&gt;Add&lt;/code&gt;, which specifies &lt;code&gt;TraitExtensions&lt;/code&gt; as a place to look for members, and says the other parameter types can be anything. Then, because an F# function is generally expected to return something other than &lt;code&gt;unit&lt;/code&gt;, it returns the collection which can be further pipelined.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Add&lt;/code&gt; sets up the binding just like before. It says to look for a &lt;code&gt;static member&lt;/code&gt; on &lt;code&gt;^t&lt;/code&gt; or &lt;code&gt;^a&lt;/code&gt; called &lt;code&gt;Add&lt;/code&gt;, with the signature &lt;code&gt;^a * ^b -&amp;gt; unit&lt;/code&gt;. Because &lt;code&gt;^t&lt;/code&gt; is always &lt;code&gt;TraitExtensions&lt;/code&gt;, then what is being said is specifically: Look on &lt;code&gt;TraitExtensions&lt;/code&gt; and the type of &lt;code&gt;collection&lt;/code&gt; for the &lt;code&gt;static member&lt;/code&gt;: &lt;code&gt;Add : ^a * ^b -&amp;gt; unit&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We now have a function, &lt;code&gt;add (elements) (collection)&lt;/code&gt; which will work for &lt;em&gt;any&lt;/em&gt; collection of &lt;code&gt;IAddable&amp;lt;TElement&amp;gt;&lt;/code&gt;, and allow adding any of the overloads of &lt;code&gt;elements&lt;/code&gt; defined in &lt;code&gt;IAddable&amp;lt;TElement&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;No seriously. Here's examples lifted directly out of my F# unit tests.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DynamicArray&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Int32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
&lt;span class="nn"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;p&gt;&lt;span class="kt"&gt;array&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ignore&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="nn"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
&lt;span class="nn"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;.[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="kt"&gt;array&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;add&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="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;|]&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ignore&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="nn"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
&lt;span class="nn"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;.[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;br&gt;
&lt;span class="nn"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Equal&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="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;.[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;br&gt;
&lt;span class="nn"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Equal&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="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;.[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;br&gt;
&lt;span class="nn"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;.[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;br&gt;
&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Summary&lt;br&gt;
&lt;/h1&gt;

&lt;p&gt;Part of what I find brilliant about this solution is not only are the F# bindings easier to write, they're also easier to maintain. Previously, I struggled with ensuring there was strict 1:1 parity between them, but now that &lt;em&gt;just happens&lt;/em&gt; every time I add new overload. While this approach would add work to very small libraries, it reduced the amount of code by roughly 11% (I'm not done some changes and don't have a precise number) without removing a single feature.&lt;/p&gt;

&lt;p&gt;Would this be easier the other way around? Implement in F# and provide C#/VB bindings? I'm not sure, but it's something I'm very interested in and need to explore. Certain features F# was lacking kept me from trying this before, but with F# 5.0 I believe everything I need is now present. This, and some other things will be a topic for the future.&lt;/p&gt;

&lt;p&gt;Now, let me be clear: this still isn't the most ideal situation. What I would love is for the C# team to provide ways to generate the same metadata F# uses. Things like being able to decare a C# static method has a curried form that F# can use without any bindings necessary. But with the current state of things, if you have to implement in C# and want to provide good functional and pipeline focused experiences for F# consumers, this seems to be one of the better ways to go about it.&lt;/p&gt;

&lt;h1&gt;
  
  
  Going Further
&lt;/h1&gt;

&lt;p&gt;Just a few days before this article, I came across &lt;a href="https://github.com/gusty"&gt;Gustavo Leon&lt;/a&gt;'s experiment with &lt;a href="https://gist.github.com/gusty/b6fac370bff36a665d75"&gt;Variadic Functions&lt;/a&gt;. I've come to expect flack from some of the more purist/fundamentalist members of the F# community, so I don't mind talking about this and even experimenting with whether it's useful in this context. Is it a "haskellism"? Yes. Is it potentially useful in this context? Yes. Should it be done in a pure F# context? Probably not. I'll report back later on whether F#-first/C#-bindings or variadic functions have uses in the context of multi-language libraries.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>fsharp</category>
    </item>
    <item>
      <title>The (non) Monorepo Mistake</title>
      <dc:creator>Patrick Kelly</dc:creator>
      <pubDate>Sat, 24 Oct 2020 19:28:47 +0000</pubDate>
      <link>https://dev.to/entomy/the-non-monorepo-mistake-16ba</link>
      <guid>https://dev.to/entomy/the-non-monorepo-mistake-16ba</guid>
      <description>&lt;p&gt;I messed up and am paying the price for it. Hopefully, others can learn from my mistake. Everything I've been working on should have been in a monorepo, and I didn't do that.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I did the &lt;strong&gt;opposite&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Let me just get this out there right now. This is &lt;em&gt;not&lt;/em&gt; going to be explaining why &lt;em&gt;you&lt;/em&gt; should use a monorepo. There's a good chance you &lt;em&gt;should not&lt;/em&gt;. This is why &lt;em&gt;I should have&lt;/em&gt;. And even more specifically, why I should have for only &lt;em&gt;one&lt;/em&gt; project. I have other projects that should stay discrete repos.&lt;/p&gt;

&lt;p&gt;The benefits of monorepos are well documented. &lt;a href="https://devblogs.microsoft.com/startups/using-monorepos-to-increase-velocity-during-early-stages-of-product-development/"&gt;[1]&lt;/a&gt; &lt;a href="http://danluu.com/monorepo/"&gt;[2]&lt;/a&gt; &lt;a href="https://www.happycoders.eu/java/monorepos-advantages-disadvantages/"&gt;[3]&lt;/a&gt; &lt;a href="https://presumably.de/monorepos-and-the-fallacy-of-scale.html"&gt;[4]&lt;/a&gt;. So are the detriments. &lt;a href="https://medium.com/@mattklein123/monorepos-please-dont-e9a279be011b"&gt;[1]&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since I didn't, let's go over why I didn't first, but then what I learned each time. Following along with Matt Kleins excellent article:&lt;/p&gt;

&lt;h1&gt;
  
  
  Theoretical monorepo benefits...
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Easier collaboration...
&lt;/h2&gt;

&lt;p&gt;I actually disagreed with this for much of the same reasons Klein disagrees with it. In fact, I still do. But I'd even go further to add that very large repos are intimidating to collaborators and increases the burden of onboarding. There's part of what I learned that shoots a hole straight through this argument though. Klein states "or to search through it using tools like grep ... must provide ... sophisticated source code indexing/searching/discovery capabilities as a service". Well, yeah, exactly! Any time I need to look through the .NET Core runtime, it's a huge PIA. It's hopeless to try to find your way and you have to rely on search tools. Break things apart and you can navigate manually far easier. So this is a good thing, right! The fallacy here is that discoverability is a function of modularity or lack-thereof, when it is in fact a function of the overall size of the code base. Breaking it apart introduced an even bigger problem. With code split across repo boundaries, search tools would fail. And you were still left with navigation problems just with a different level of abstraction. What was "what folder might this be in" was changed to "what repo might this be in". I didn't solve anything, I just traded some problems for others. The problems I had before were already solved by in-editor tooling, and are therefore preferable. Where he states "given that a developer will only access small portions .. is there any real different between checking out a small portion or checking out multiple repositories..."; I agree with this for the most part, this is more of a prodecural than functional thing and has little significant effect to ops. He further goes on to state "In terms of source code indexing/..." which is absolutely correct. However, this requires contributors to be familiar with an additional tool, and even worse, a tool that exists outside of the editor they are familiar with, to navigate your overall project. With the monorepo everything is searchable with the tooling you should already be familiar with, and, importantly, works the way you've gotten familiar with. You &lt;em&gt;don't&lt;/em&gt; need additional tooling in this instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Single build...
&lt;/h2&gt;

&lt;p&gt;No, he's entirely right here from my experiences. The build tools that work well for monorepos dgaf and work well for submoduling or other polyrepo styles. Furthermore, there's also techniques to pull off a single build pipeline of multiple discrete repos in various DevOps solutions. This purported benefit is highly dubious.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code refactors...
&lt;/h2&gt;

&lt;p&gt;He rightfully points out a fallacy but also falls prey to the fallacy of scale himself. I still question the efficacy of massive monorepos like Google does. However, in my case we're talking a small monorepo that's completely reasonable to check out the entire thing on a single machine.&lt;/p&gt;

&lt;p&gt;But I'd also like to address a few points. "a developer can clone and edit the entire codebase ... how often does that actually happen?" In my case, actually quite often, as adding a new feature may potentially involve adding subfeatures in numerous locations. As I'm adding in a serialization framework right now, this involves adding files to Defender, Collectathon, and Philosoft, because the overall feature spans multiple scopes. And because serialization is useless without the ability to stream the serialized data, whether to disk or across the network, this necessary addition also needs to be added to the streams API I've written. Whether the core stream API remains in Stringier is still unknown, but regardless, this feature spans across the entire overall project. "They can give up, and work around the API issue...", I was actually doing this far more with things split up polyrepo style. As I merge things into the monorepo I'm finding numerous cases where I've done this and am syncing everything back up.&lt;/p&gt;

&lt;h1&gt;
  
  
  Unique monorepo downsides
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Tight coupling...
&lt;/h2&gt;

&lt;p&gt;He opens with "a monorepo encourages tight coupling", to which I can say, yes I believe this does. However that's why I'm trying to find a very careful boundary for this, because I have code that &lt;em&gt;is&lt;/em&gt; very tightly coupled.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;But tight coupling is bad!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hol' up. Let me explain real quick what's going on here and we'll address this point again. Stringier, Collectathon, Defender, and others are part of an overall project where I'm developing a language runtime and standard library for a DSL I've needed. That language is being developed with cross-language compatibility in mind, and is part of why it's being developed with .NET languages, because of CLS compliance. A language runtime is inherently tightly coupled. This being said, reducing coupling is always a good thing, and I've been fighting to find various boundaries. Historically, Stringier was broken up into multiple subprojects but I've been undoing that. However, the aforementioned projects are hard boundaries that I've identified and have not struggled with since. This is why I can do things like write an article about using guard clauses and how Defender offers these, and not having to explain how this ties directly to or is dependent on other things. Because of modularity and CLS compliance, these components are available to other consumers like C# and F#.&lt;/p&gt;

&lt;p&gt;So is coupling bad? Well, there's a sweet spot. I could potentially go through an insane amount of decoupling where each individual function is its own project with its own artifact that's published as a nuget package. But that's insane and imposes an inordinant amount of additional work on me. Some level of coupling enables efficient compatibility. Let's look at it this way: If a contractor built your house without any bolts or nails you'd be concerned, and "But coupling is bad and I've ensured everything is modular" would be anything but reassuring. But you can definately couple way too much as well. If you walked into your new home and your furniture was bolted to the floor, that would be equally concerning for entirely different reasons. There's an ideal amount of coupling that's important, and too much or too little is problematic in their own ways.&lt;/p&gt;

&lt;p&gt;Klein then says, "If an organization wishes to create or easily consume OSS, using a polyrepo is required.". This one in particular bugs me. Scale might be important here, because I found the exact opposite. I shot myself in the foot by splitting things up. Where I originally thought I would be making things easier to navigate and discover, I actually trashed the amount of navigation to my repo. I can safely say trashed because as I merge things back into a single repo, I'm back up to the traffic numbers I was at before.&lt;/p&gt;

&lt;h1&gt;
  
  
  VCS scalability
&lt;/h1&gt;

&lt;p&gt;"Scaling a single VCS to hundreds of developers, hundreds of millions lines of code, and a rapid rate of submissions is a monumental task.", completely agreed, although I'd add that scaling anything to that size is a monumental task.&lt;/p&gt;

&lt;h1&gt;
  
  
  Other arguments.
&lt;/h1&gt;

&lt;p&gt;We're done with Kleins article and this has to do with other things I've read or heard that shaped my decision, to which I'm now backtracking on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dependencies
&lt;/h2&gt;

&lt;p&gt;Okay, this is straight up bullshit right? Dependabot can keep polyrepo dependencies up to date no problem.&lt;/p&gt;

&lt;p&gt;And it can. But that's missing a key thing. However, it's a key thing in my case that I've never heard about once. In the majority of cases, good use of Dependabot can completely avoid this purported claim.&lt;/p&gt;

&lt;p&gt;So what's my case? Analyzers. I make extensive use of analyzers for code review. There's a lot of them that are suppressed, sure, either at the local level because of a specific exception, or at the project level because of disagreement with that specific analyzer. In any case, there's a justification for the suppression that goes along with it. In many of these cases, that justification is that the issue is complex and requires human review to adequately assess. The majority of analyzers still stand, diligently doing their job of helping me manage an absurdly large and still growing codebase for a single person. As I learn of more and more useful analyzers, I'd add them to the projects. With the polyrepo set up, these analyzers have to be added to each project within each repo. This is obviously less than ideal and meant the analyzers were out of sync. Not in that the version numbers were out of sync; no, Dependabot kept that in order. But rather, different projects were using different analyzers. Some are quick to jump on the fact that Visual Studio can install many of these analyzers as extensions and apply them to any project. This has several faults. Firstly, it assumes I use Visual Studio, which I do. Secondly, it assumes I &lt;em&gt;only&lt;/em&gt; use Visual Studio, which I don't. Thirdly, it assumes I'm going to keep my extensions in sync across all my Visual Studio installs, which is just the exact same problem at a different level. How does the monorepo help in this instance? &lt;a href="https://docs.microsoft.com/en-us/visualstudio/msbuild/customize-your-build?view=vs-2019"&gt;&lt;code&gt;Directory.Build.props&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://docs.microsoft.com/en-us/visualstudio/msbuild/customize-your-build?view=vs-2019"&gt;&lt;code&gt;Directory.Build.targets&lt;/code&gt;&lt;/a&gt;! These inject, at various times, properties to all projects within that directory. Put at the top level, it ensures every project is utilizing the same analyzer. This had other unintended benefits of course, such as being able to set properties for repo url, project url, copyright date, and others universally, also keeping those in sync.&lt;/p&gt;

&lt;h2&gt;
  
  
  Documentation
&lt;/h2&gt;

&lt;p&gt;I never see this brought up, ever. Documentation is incredibly easier to deal with in the monorepo setting. Just add in a single project, remove the template sources you probably had, add in a &lt;code&gt;docfx&lt;/code&gt; dependency, build it once to set up the scaffolding, and then configure it as appropriate. Now, every single build will build your docs, keeping them in sync. This might be a bit tedious for development purposes, so what I do is set the configuration to not build this in debug mode, and build it in release mode. Since I upload nuget packages in release mode, this ensures the docs are built and up-to-date on the releases.&lt;/p&gt;

&lt;p&gt;As I mentioned, however, I've been merging everything into a monorepo. So I wasn't using a monorepo before. How'd I deal with docs?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cries in DevOps&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There was three repos dealing with documentation. One held articles, one held the built documentation, and one held the documentation project. There was a build pipeline that would check out the documentation project, clone the articles repo into it, clone the build documentation into it, clone all the actual projects into it, proceed to build the documentation, make a commit of the built documentation and then push that documentation. Note that this implicitly requires everything I mentioned for the monorepo case above.&lt;/p&gt;

&lt;p&gt;I supposed this is a bit easier for me to see, since I'm wearing so many hats in this project. The monorepo isn't &lt;em&gt;only&lt;/em&gt; about the developer. Documentation was immensely simpler and easier to keep in sync in the monorepo case.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;Specifically I'm gonna talk about test &lt;em&gt;coverage&lt;/em&gt;. It's easier to calculate and more correct in the coverage numbers when you have all the sources present. That's all.&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;In summary, this was the right decision for me, although I'm sure there'll be refinements as time goes on, just as there has already been. No project is the same, and it takes experience to determine what exactly works best for any given project.&lt;/p&gt;

&lt;p&gt;Is this the right decision for you? Well, I'm nowhere near presumptuous enough to tell you what you should do. If my reasons make sense to you then maybe it is. If my reasons seem like I'm an idiot, then maybe I am, and maybe you shouldn't use a monorepo. These are my reasons, and I'm only explaining my reasons. &lt;/p&gt;

</description>
      <category>architecture</category>
    </item>
    <item>
      <title>Avoiding Nulls with Extension Methods</title>
      <dc:creator>Patrick Kelly</dc:creator>
      <pubDate>Wed, 14 Oct 2020 21:08:19 +0000</pubDate>
      <link>https://dev.to/entomy/avoiding-nulls-with-extension-methods-3mkc</link>
      <guid>https://dev.to/entomy/avoiding-nulls-with-extension-methods-3mkc</guid>
      <description>&lt;p&gt;I've programmed in Ada more and longer than C#. Something that always bugged me about any .NET or really any heavily object-oriented language was how your rate of null-dereferences shoots through the roof. Considering how I can probably have no null dereferences in a non-trivial Ada program, it was particularly weird hearing .NET programmers complain about this so much, and as I used C# more, it annoyed me as well.&lt;/p&gt;

&lt;p&gt;But the problem isn't the languages themselves; although this statement is very pedantic. Rather, it's a result of the design patterns those languages encourage.&lt;/p&gt;

&lt;p&gt;Let's show off a little about how things are done, and the problem should start to become clear.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Move&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Move&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;The problem is you didn't initialize p!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yes, in this specific extremely trivial case, and in the most pedantic sense, that is the problem. The point is, how we're calling &lt;code&gt;Move()&lt;/code&gt;. Say &lt;code&gt;p&lt;/code&gt; was actually an iteration variable in a collection of people. You queried a database and got sent back an &lt;code&gt;IEnumerable&amp;lt;Person&amp;gt;&lt;/code&gt;. Or, it could be a deserialized object, even though that should be throwing an exception, but hey, most serializers aren't written well. We're getting &lt;code&gt;p&lt;/code&gt; somehow and code flow analysis alone can't say it's not null.&lt;/p&gt;

&lt;p&gt;That's just the way it is, right? This is why null chaining exists. What I really should be doing is &lt;code&gt;p?.Move()&lt;/code&gt;, obviously!&lt;/p&gt;

&lt;p&gt;But this doesn't sit right with me. As a developer primarily writing other libraries, I try to make the callsites as easy and error-proof as possible. Forgetting to use &lt;code&gt;?.&lt;/code&gt; instead of &lt;code&gt;.&lt;/code&gt; is just too easy. It's not easy to grep the problem. And putting &lt;code&gt;?.&lt;/code&gt; &lt;em&gt;everywhere&lt;/em&gt; is actually problematic for its own reasons.&lt;/p&gt;

&lt;p&gt;But that's just the way it is, right? &lt;strong&gt;&lt;em&gt;No&lt;/em&gt;&lt;/strong&gt;!&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ada"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nf"&gt;Person&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;tagged&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;--fieldless "class"&lt;/span&gt;

&lt;span class="kd"&gt;procedure&lt;/span&gt; &lt;span class="nf"&gt;Move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Self&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Move&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;--object.Method() style&lt;/span&gt;
&lt;span class="n"&gt;Move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;--Procedure(object) style&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Neither of these will throw a null dereference exception!&lt;/p&gt;

&lt;p&gt;Now a huge part of this has to do with language semantics. Ada initializes all objects upon declaration even without an explicit declaration, although analyzers will generally report this with a warning or error still. Obviously we can't change C# semantics. So while this is great, we can't do much about this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Aw61j1pq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/w7uwngdrxcuyb95tbwh1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Aw61j1pq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/w7uwngdrxcuyb95tbwh1.png" alt="Zoidberg: hol' up"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's a solution and good lord is it obtuse. If you're cranking out products for clients then this isn't going to be the least bit useful for you. But if you're a library author this may be of interest.&lt;/p&gt;

&lt;p&gt;Notice one thing about Ada's function/procedure declaration. Even if it's dispatching off a type, we're still explicitly declaring that parameter. Do we have something like this in C#? Yes! The &lt;a href="https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods"&gt;extension method&lt;/a&gt;. So let's try this again.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Move&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Operations&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Move&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Move&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;//This is still Person.Move, not Operations.Move&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Uh oh. Problem is, instance methods are preferentially resolved; they are checked before extension methods. We &lt;em&gt;could&lt;/em&gt; &lt;code&gt;using static Operations&lt;/code&gt; and call with &lt;code&gt;Move(p)&lt;/code&gt; everywhere, but that's very anti-C#. There's a solution though, and it's a simple visibility change.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;internal&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Move&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Operations&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Move&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Move&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;//This is Operations.Move now!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Fantastic. Although we're only redirecting a call at this point. We'll still get a null dereference exception. How do we gracefully handle &lt;code&gt;null&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--M3TqJMNB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jmobyfn4ycnbq2d6bmez.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--M3TqJMNB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jmobyfn4ycnbq2d6bmez.png" alt="Newton invents calculus"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's not actually a joke. There's a simple calculus to explain this, and it's so simple I don't even need to get all theoretical, just a bit metaphysical.&lt;/p&gt;

&lt;p&gt;If we move &lt;em&gt;nothing&lt;/em&gt;, what happens? Well, &lt;em&gt;nothing&lt;/em&gt; happens. What is &lt;code&gt;null&lt;/code&gt;? A pointer/reference to &lt;em&gt;nothing&lt;/em&gt;. So an operation upon &lt;em&gt;nothing&lt;/em&gt; does &lt;em&gt;nothing&lt;/em&gt;. We can codify this like so:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;null&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="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Move&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;Now a call to &lt;code&gt;p.Move()&lt;/code&gt; will either move &lt;code&gt;p&lt;/code&gt; as described by &lt;code&gt;Person.Move()&lt;/code&gt; &lt;em&gt;or&lt;/em&gt; will do nothing.&lt;/p&gt;

&lt;p&gt;If you have a return type, it's a little different. But the same line of metaphysical thinking reveals the answers. If you're counting occurrences of something in a collection, and the collection is empty, how many occurrences are there? Well, &lt;code&gt;0&lt;/code&gt;, obviously. More tangibly, if you're counting the amount of apples you have in a bag, and the bag is empty, how many apples are there? &lt;code&gt;0&lt;/code&gt;. If you're counting the amount of apples in a bag, and you don't have the bag, how many apples are there in the bag you don't have. &lt;code&gt;0&lt;/code&gt;. Remember, it's a bag that doesn't exist, not a bag that you don't own.&lt;/p&gt;

&lt;p&gt;Do I see this as useful for most people? No absolutely not. More than anything, this is a neat curiosity. But it's certainly something for library authors to keep in mind. I can definitely see this being interesting for things which focus very highly on usability, as this helps avoid many cases of errors. But do note that not every method should be "null proof" like this. There are methods which absolutely should be called off the instance itself and need to throw a null dereference exception as part of their semantics. This is just a neat tool for those looking to increasingly harden their API's.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Functional Collections</title>
      <dc:creator>Patrick Kelly</dc:creator>
      <pubDate>Sun, 11 Oct 2020 17:47:51 +0000</pubDate>
      <link>https://dev.to/entomy/functional-collections-36ci</link>
      <guid>https://dev.to/entomy/functional-collections-36ci</guid>
      <description>&lt;p&gt;Next up in &lt;a href="https://github.com/Entomy/Collectathon"&gt;&lt;strong&gt;Collectathon&lt;/strong&gt;&lt;/a&gt; is something I've seen quite a large amount of programmers express a desire for, although I didn't quite implement it to the extent they express. I'll explain why as I explain what this is.&lt;/p&gt;

&lt;p&gt;Functional Programming is a small but very vocal and influential paradigm. I'll admit, I have mixed feelings about it. It's rife with performance problems, and puts the burden of knowledge on the downstream programmer which I consider an unreasonably UX. I feel like it's the wrong level of abstraction in most cases, with either declarative or imperative being more suitable. But it does have some fantastic parts, and it'd be great to incorporate them. Of especial interest here is higher-order functions. &lt;a href="https://github.com/Entomy/Collectathon"&gt;&lt;strong&gt;Collectathon&lt;/strong&gt;&lt;/a&gt; offers these.&lt;/p&gt;

&lt;p&gt;Most collections are enumerable, the ones that aren't implement &lt;a href="https://entomy.github.io/Collectathon/api/Collectathon.Traits.IContainable-1.html"&gt;&lt;code&gt;IContainable&amp;lt;TElement&amp;gt;&lt;/code&gt;&lt;/a&gt;, and in many cases, both are true. No matter what, this means that a collection has a &lt;code&gt;Contains()&lt;/code&gt; method supplied from &lt;em&gt;somewhere&lt;/em&gt;. Every collections library out there supports testing if a collection contains a specific element. That's simple and straightforward. I don't think a collections library would be very usable without it. But what about whether a collection has any elements that meet some specific criteria? Collections are generic, far too generic for a declarative API to be possible. This is Functional Programming's ideal niche!&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;DoublyLinkedList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DoublyLinkedList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;True&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IsPrime&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// Assuming IsPrime() exists&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This example is a bit contrived, but it can be especially useful. Consider seeing if a collection of customers has any customers of a specific geographic region.&lt;/p&gt;

&lt;p&gt;In fact, any method where accepting a predicate makes sense should have an overload that accepts a predicate. Methods like &lt;code&gt;IndexOf()&lt;/code&gt;, &lt;code&gt;Occurrences()&lt;/code&gt;, &lt;code&gt;Remove()&lt;/code&gt;, and &lt;code&gt;Replace()&lt;/code&gt; already have higher-order variants defined.&lt;/p&gt;

&lt;p&gt;Functional Programming also defines some well understood conventional functions as well though, and &lt;a href="https://github.com/Entomy/Collectathon"&gt;&lt;strong&gt;Collectathon&lt;/strong&gt;&lt;/a&gt; intends to support these in their entirety. Currently defined are functions like &lt;code&gt;Map()&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;DynamicArray&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DynamicArray&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;((&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It works! I'm not happy about the callsite in C#. It's ugly and there's no other way to put that. I'm still looking into options to get that to resolve without being explicitly told what the types are. Maybe &lt;code&gt;Map()&lt;/code&gt; must be supported via its own trait rather than implemented with existing traits (It currently requires &lt;code&gt;ICountable&lt;/code&gt; and &lt;code&gt;IIndexable&amp;lt;Int64, TElement&amp;gt;&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;However, this is a fantastic opportunity to bring up what I've been doing for the people most likely to be using a functional paradigm anyways: F# bindings!&lt;/p&gt;

&lt;p&gt;That same operation in F# looks like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DynamicArray&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Int32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="p"&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="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;|]&lt;/span&gt;
            &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&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="nn"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Equal&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="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;|],&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;No explicit types! Which makes total sense as F# is meant for this kinda stuff. And these F# functions aren't their own implementations; they &lt;em&gt;are&lt;/em&gt; the existing definitions, just with a little marshalling as appropriate.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="nc"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&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;^&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="o"&gt;(^&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;a&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;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="nc"&gt;Add&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&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;^&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt;&lt;span class="o"&gt;)&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="o"&gt;((^&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;a&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;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="nc"&gt;Add&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&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;^&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt; 
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="nc"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;_,&lt;/span&gt; &lt;span class="o"&gt;_&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;
        &lt;span class="n"&gt;collection&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="nn"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Func&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;_,&lt;/span&gt; &lt;span class="o"&gt;_&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;collection&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Similarly, &lt;code&gt;Fold()&lt;/code&gt; is supported right now, but &lt;code&gt;FoldLeft()&lt;/code&gt; and &lt;code&gt;FoldRight()&lt;/code&gt; aren't. How does that work? Well, &lt;code&gt;Fold()&lt;/code&gt; requires the delegate to be a magma, while the other two require left-associative or right-associative respectively. The most common case of folding is the magma fold, so it made sense to implement this first.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DynamicArray&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Int32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="p"&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="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;|]&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;fold&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="nn"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;There's still that nagging part of me that wants this to be declarative even though that requires an exponential amount of work. A single magma &lt;code&gt;Fold()&lt;/code&gt; can support all kinds of operations, whereas a declarative &lt;code&gt;Sum()&lt;/code&gt; only works for the single numeric type for which it was defined. It does conveniently express intent better, and not require the downstream programmer to know what the delegates identity is (&lt;code&gt;0&lt;/code&gt; for addition). In some cases, determining identity is remarkably difficult. But I'm glad this exists. This is a hugely powerful, and to reiterate, appropriate for this level of abstraction.&lt;/p&gt;

&lt;p&gt;Consider all this another tool in the toolbox &lt;a href="https://github.com/Entomy/Collectathon"&gt;&lt;strong&gt;Collectathon&lt;/strong&gt;&lt;/a&gt; provides.&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>functional</category>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Proper Sets</title>
      <dc:creator>Patrick Kelly</dc:creator>
      <pubDate>Tue, 06 Oct 2020 15:09:42 +0000</pubDate>
      <link>https://dev.to/entomy/proper-sets-4p0b</link>
      <guid>https://dev.to/entomy/proper-sets-4p0b</guid>
      <description>&lt;p&gt;A while ago I wrote about how &lt;a href="https://dev.to/entomy/iset-t-considered-harmful-2hpd"&gt;&lt;code&gt;ISet&amp;lt;T&amp;gt;&lt;/code&gt; should be considered harmful&lt;/a&gt;. While criticisms are absolutely valid, it's even better if I can show a better solution that avoids these problems.&lt;/p&gt;

&lt;p&gt;Enter &lt;a href="https://entomy.github.io/Collectathon/api/Collectathon.DataStructures.Sets.Set-1.html"&gt;&lt;code&gt;Set&amp;lt;TElement&amp;gt;&lt;/code&gt;&lt;/a&gt;. I'm still not 100% sure on the public API, and this whole project is still in beta anyways, so if you've got a better idea on how to do something I show off, please let me know so I can look into it.&lt;/p&gt;

&lt;p&gt;First off, there is no interface. Rather, this is an abstract type from which you can derive, but has internal derivations within the library that you can't directly access but will wind up working with. I promise this makes sense in practice.&lt;/p&gt;

&lt;p&gt;Instead of the typical way I see sets implemented, this isn't a mutable data structure. Rather, what elements it starts with are there forever. Instead, you build up more complex sets through set algebra, which has well defined axioms, and identities that can be utilized. But let's cover the most basic sets first.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;smallPrimes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;From&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;7&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, &lt;code&gt;smallPrimes&lt;/code&gt; cannot change, both in that the instance isn't mutable, and the reference is &lt;code&gt;readonly&lt;/code&gt;. Testing for existence within a set is simple and obvious.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;True&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;smallPrimes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;False&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;smallPrimes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;False&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;smallPrimes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;But there's another type of simple set that we should cover! Consider how, with &lt;code&gt;ISet&amp;lt;T&amp;gt;&lt;/code&gt; one would define a set of all even or odd numbers, or even just all numbers! The standard set of even numbers for a 32-bit integer would use up 8,589,934,588 bytes of memory! I don't know about you but I don't have a computer than can use that approach. I'm not Microsoft with millions of dollars spent on server farms and distributed computing technologies to allow for that. Maybe that's why they weren't concerned about it? 🤔&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;evens&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;From&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Congratulations, you now have a set of all even numbers, and it doesn't explode your computer!&lt;/p&gt;

&lt;p&gt;Let's also consider the following sets:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;odds&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;From&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;positive&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;From&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;negative&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;From&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;empty&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;universe&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Universe&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The empty set is obvious: it's a set with no elements. The universe isn't so obvious, but it's the compliment of the empty set: it's a set with &lt;em&gt;all&lt;/em&gt; elements.&lt;/p&gt;

&lt;p&gt;That's right, we've defined sets for every single number, every single even number, and every single odd number, all in single lines of code.&lt;/p&gt;

&lt;p&gt;Remember how in algebra class there were identities? These were typically &lt;code&gt;0&lt;/code&gt; or &lt;code&gt;1&lt;/code&gt;, like how &lt;code&gt;x/x = 1&lt;/code&gt; or &lt;code&gt;x-x = 0&lt;/code&gt; or &lt;code&gt;x+0 = x&lt;/code&gt;. They are extremely useful for math overall, and the centuries without identities and &lt;code&gt;0&lt;/code&gt; especially were rife with problems. Well, in set algebra the empty set and universe set are those identities. Trying to do set algebra without these identities is like trying to do abstract algebra (the stuff you learned in school) without &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt;. You're gonna have a bad time!&lt;/p&gt;

&lt;p&gt;So let's use these in some simple algebraic operations.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;positiveEvens&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;positive&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;evens&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here, we just did the intersection between all positive numbers and all even numbers. Any negative numbers, even or odd, will not test true for existence, even though one of the constituent sets would.&lt;/p&gt;

&lt;p&gt;There's a useful way to understand the operators used for this: what operator would you use for testing existence in two arrays? In this case, you loop through the "positive array" and loop through the "even array", and only if it's in both, is it part of the set.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;oddsWithoutSmallPrimes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;odds&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;smallPrimes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here, we just did the difference between the set of odd numbers and the set of all small prime numbers. So you don't have to scroll up, &lt;code&gt;smallPrimes&lt;/code&gt; was defined as &lt;code&gt;[2, 3, 5, 7]&lt;/code&gt;. Taking &lt;code&gt;2&lt;/code&gt; out of all odd numbers doesn't do anything, because it was never in there to begin with. Taking the rest out makes then test false instead.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;True&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oddsWithoutSmallPrimes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;False&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oddsWithoutSmallPrimes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;False&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oddsWithoutSmallPrimes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;False&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oddsWithoutSmallPrimes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;False&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oddsWithoutSmallPrimes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;True&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oddsWithoutSmallPrimes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;True&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oddsWithoutSmallPrimes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Hopefully this makes sense.&lt;/p&gt;

&lt;p&gt;Overall, the following set operations have been defined with the corresponding C# operators.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;C#&lt;/th&gt;
&lt;th&gt;Set Operation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Difference&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;!&lt;/td&gt;
&lt;td&gt;Complement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;amp;&lt;/td&gt;
&lt;td&gt;Intersection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;^&lt;/td&gt;
&lt;td&gt;Disjunction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;|&lt;/td&gt;
&lt;td&gt;Union&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Again, every operator was chosen to correspond with the equivalent logical operator that would be performed if testing these yourself. Except &lt;code&gt;-&lt;/code&gt; of course, where that's the difference just like in abstract algebra.&lt;/p&gt;

&lt;p&gt;So how does all this work? Through expression trees. It's worth pointing out that this has nothing to do with the &lt;a href="https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/expression-trees/how-to-use-expression-trees-to-build-dynamic-queries"&gt;LINQ expression trees&lt;/a&gt;. Rather, this is an actual data structure, itself a type of multiway tree. Any literal set is not modified, but set operators build up a tree representing the expression as you wrote it, and return that tree as a new set. This seems expensive at first, but remember how much memory using a delegate to describe the set saves? Expression trees can actually yield even more savings, although only above very simple usage. Because each set is immutable, we can freely reuse them across sets, which means arbitrary composition of sets reuses existing instances, saving even more memory. &lt;em&gt;Fantastic&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Now what about cases where you want a list or tree or whatever, of unique elements. If the element is already in the collection, it shouldn't be added again. Well I got news for you. That's not a set. That's a &lt;em&gt;unique&lt;/em&gt; whatever-the-base-collection-was, which is its own concept. Combining the two is a huge part of why the &lt;code&gt;ISet&amp;lt;T&amp;gt;&lt;/code&gt; abstraction is so convoluted and irregular.&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Linked Lists</title>
      <dc:creator>Patrick Kelly</dc:creator>
      <pubDate>Thu, 01 Oct 2020 12:02:22 +0000</pubDate>
      <link>https://dev.to/entomy/linked-lists-13gi</link>
      <guid>https://dev.to/entomy/linked-lists-13gi</guid>
      <description>&lt;p&gt;Last time, we covered variations of advanced arrays. I mentioned ways of achieving degrees of flexibility, but also mentioned there were some strong limitations. When you need even more flexibility, but your data still &lt;em&gt;looks&lt;/em&gt; like an array, you need linked lists.&lt;/p&gt;

&lt;p&gt;As a quick aside, some people will be quick to bring up binary trees for this because "faster indexing", and while that's true in the most naive cases, it's &lt;em&gt;only&lt;/em&gt; true in the most naive cases. We'll get to that.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;code&gt;SinglyLinkedList&amp;lt;TElement&amp;gt;&lt;/code&gt; and &lt;code&gt;SinglyLinkedList&amp;lt;TIndex, TElement&amp;gt;&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;Just like with the arrays, we have both a standard and associative variant. This time, however, we don't have an array, even though the overall API is extremely similar. &lt;a href="https://github.com/Entomy/Collectathon"&gt;&lt;strong&gt;Collectathon&lt;/strong&gt;&lt;/a&gt; even utilizes an approach to ensure what APIs are implemented are exactly identical. So what's these links and why is it single?&lt;/p&gt;

&lt;h2&gt;
  
  
  Linkage
&lt;/h2&gt;

&lt;p&gt;One of the most common strategies for implementing dynamic data structures is linkage of nodes, and, in fact, you can create nearly any structure with this approach. The idea is, you have nodes that hold an element in the collection, but that also hold pointers or references to other nodes. What's a node?&lt;/p&gt;

&lt;h2&gt;
  
  
  Nodes
&lt;/h2&gt;

&lt;p&gt;Nodes are aggregate data structures, like &lt;code&gt;struct&lt;/code&gt; or &lt;code&gt;class&lt;/code&gt; with fields for elements and fields for links. In the most basic sense, a node will contain a single element, but it doesn't always have to be this way. The amount of links and the direction of them are completely arbitrary.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works?
&lt;/h2&gt;

&lt;p&gt;Let's start with an empty list, since we can feasibly do that now, and build up a small list.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;SinglyLinkedList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;SinglyLinkedList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// List is now: []&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// List is now: [2]&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// List is now [2,4,5,6]&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// List is now [2,3,4,5,6]&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// List is now [1,2,3,4,5]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Every time we added a new node, regardless of how we did it, we did several things under the hood. First, since this is .NET we're talking about, all these live on the heap, so there's heap allocations associated with each. Second is, regardless of where the data is stored, each value has a hidden extra cost: the links. While the singly-linked list is the most compact simple list, each node holds a reference to the next node. This means that at the end of just a few operations, our list is using up 480 bits of memory on a 64-bit computer, while the array would only be using up 160 bits. Actually, I lied. It's worse than you probably thought. Because we can't create the nodes through &lt;code&gt;unmanaged&lt;/code&gt; structs, each node has a tag that also uses up memory, although the amount is hard to determine. On top of that, the 480 bits was only how much the nodes used up, because the list object is also going to use up space! Not only for its own tag, but also an additional 192 bits for two references and a counter. That sounds horrible but hold on. When I was explaining arrays I said that the allocate-copy-swap-deallocate resizing technique that dynamic arrays use was extremely expensive. That's what lists address. If you're doing a lot of resizing, which is quite common, linked lists are the preferrable data structure. Singly-linked lists are an attempt at compromising on this, because they use less memory than their more commonly used counterpart, at the expense of a feature that's easier to explain when explaining the counterpart.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;code&gt;DoublyLinkedList&amp;lt;TElement&amp;gt;&lt;/code&gt; and &lt;code&gt;DoublyLinkedList&amp;lt;TIndex, TElement&amp;gt;&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;Double-linkage addresses a shortcoming of single-linkage that doesn't effect everyone, but if it effects you there's no effective way around it. While a single link points to the next node, how do you move back? Double-linkage adds an additional pointer or reference for moving backwards. Doubly-linked lists don't offer much more additional functionality. Other than the possibility of a reverse enumerator, the reverse links only help optimize certain operations and even then only in certain situations. But you &lt;em&gt;pay&lt;/em&gt; for it. In our example of just 5 elements, the doubly-linked list would consume 800 bits, not including the overhead of tags on the nodes, nor the list object.&lt;/p&gt;

&lt;p&gt;Now I don't mean this as an attack on doubly-linked lists. In fact, I would recommend that you start your development with them, and only switch off after getting a stable library/application. Switch to what? Well that's why you wait. You need to understand what operations you're using, as well as profiling/benchmarking various things to make the appropriate call. Doubly-linked lists offer the overall best compromise across every factor. But they aren't the end-all-be-all. There's actually several techniques rarely seen in collections libraries for addressing this. Why? Laziness is my guess. They aren't new research in most cases.&lt;/p&gt;

&lt;h1&gt;
  
  
  Partial Unrolling
&lt;/h1&gt;

&lt;p&gt;Arrays offer exceptional performance in most situations with either inflexibility or catastrophic performance for only one operation. Simple linked lists offer great flexibility at the cost of high memory usage and reduced performance, both in real and asymptotic time. Wouldn't it be nice if we could combine them? If only.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dl.acm.org/doi/10.1145/182590.182453"&gt;Unrolling lists&lt;/a&gt; &lt;strong&gt;bam&lt;/strong&gt; straight off the presses, new research, people haven't had time to implement it yet, published in the recent... 1994. &lt;strong&gt;&lt;em&gt;1994&lt;/em&gt;&lt;/strong&gt;! I seriously have &lt;em&gt;never&lt;/em&gt; seen an implementation of the partially unrolled linked list in my life. I'm aware of two companies that had implemented them internally for certain products, but that's it. Even trying to scan Nuget for an implementation led me a dozen pages in without finding one.&lt;/p&gt;

&lt;p&gt;As of this writing I do provide &lt;a href="https://entomy.github.io/Collectathon/api/Collectathon.DataStructures.Lists.UnrolledLinkedList-1.html"&gt;&lt;code&gt;UnrolledLinkedList&amp;lt;TElement&amp;gt;&lt;/code&gt;&lt;/a&gt; but not its associative variant. There are currently some implementation problems, even though it passes the tests. It's still in beta, but it does exist.&lt;/p&gt;

&lt;p&gt;Partial-unrolling works off the idea that... yeah, let's just straight up combine them. In &lt;a href="https://github.com/Entomy/Collectathon"&gt;&lt;strong&gt;Collectathon&lt;/strong&gt;&lt;/a&gt; this is accomplished by creating a special node called a chunk, which is derived from &lt;a href="https://entomy.github.io/Collectathon/api/Collectathon.DataStructures.Arrays.BoundedArray-1.html"&gt;&lt;code&gt;BoundedArray&amp;lt;TElement&amp;gt;&lt;/code&gt;&lt;/a&gt;. This is also why we're covering these in a build-up way: the whole library is built up. When a chunk is still below a certain capacity, elements are added to the list just like they would be to an array. When the chunk grows above a certain capacity, a new chunk is allocated, linked together, and the elements are added to that one now. Essentially, it's the &lt;a href="https://entomy.github.io/Collectathon/api/Collectathon.DataStructures.Arrays.DynamicArray-1.html"&gt;&lt;code&gt;DynamicArray&amp;lt;TElement&amp;gt;&lt;/code&gt;&lt;/a&gt; only we're using up a tiny bit of extra memory to avoid the dreaded allocate-copy-swap-deallocate resizing technique. Do keep in mind though, that depending on what operations are occurring, the list may be constructed with a lot of empty spots in the arrays. If the chunk size is 32 slots, and we're using &lt;code&gt;Int32&lt;/code&gt; again, this means each chunk uses up 1024 bits before even factoring in links and tags. While partial-unrolling is a great optimization, it's potentially vulnerable to the same memory waste problem that shies developers away from arrays in the first place. Also, partial-unrolling offers a neat optimization for rapid indexing that we should talk about now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Indexing
&lt;/h2&gt;

&lt;p&gt;All linked lists are not random access collections anymore. Random access requires contiguous storage, and links add flexibility at the expense of contiguous storage. For simple lists, this means traversal through the list requires dereferencing a pointer just to move to each next node. While this should be handled for you by an iterator/enumerator/cursor, it's still happening, and you pay for that. This also means that moving to the 500th element requires dereferencing every pointer up to that point. That's a lot! For this reason, various techniques including but not limited to partial-unrolling have been developed to speed this up. With partial unrolling, random access is now possible inside of the chunk, and moving to the next chunk advances the equivalent of the chunk size in pointer dereferences as a single dereference. For a chunk size of 32, this means moving to the 500th element in 15 dereferences instead of 500. Much faster!.&lt;/p&gt;

&lt;h1&gt;
  
  
  Skip Lists
&lt;/h1&gt;

&lt;p&gt;Another strategy for optimizing linked lists is the skip list. As far as I can tell, this first showed up with &lt;a href="https://dl.acm.org/doi/10.1145/78973.78977"&gt;Skip lists: a probabilistic alternative to balanced trees&lt;/a&gt; back in 1990. This thing is as old as I am, and similarly to partial-unrolling I never seem to see it anywhere.&lt;/p&gt;

&lt;p&gt;I haven't implemented this one yet, but I need it, so it's happening.&lt;/p&gt;

&lt;p&gt;Skip lists work off the idea that you're still going to hold one element per node, but you are now going to have additional linkage in the nodes. Unlike what was done for the doubly-linked list however, these linkages all point in the same direction. Instead what we're now doing is linking ahead more than 1 element. This is the &lt;em&gt;skip&lt;/em&gt;. We're &lt;em&gt;skipping&lt;/em&gt; &lt;strong&gt;x&lt;/strong&gt; elements ahead. Exactly how this is done is up for the implementer to decide. You could keep track of the skip amount inside the node. You could keep it a fixed amount and update it with every operation that effects it. There's assorted options, but it always skips ahead. This offers superior indexing capabilities compared to simple lists, while also not introducing the possibility of unused space like with partial-unrolling. However, you do pay for those extra linkages. As always, benchmark/profile before making decisions, but from my experiences I generally switch to a skip-list when working with lists above a certain large size.&lt;/p&gt;

&lt;h1&gt;
  
  
  Jump lists
&lt;/h1&gt;

&lt;p&gt;Not to be confused with the jump list feature introduced with Windows 7!&lt;/p&gt;

&lt;p&gt;A jump list is a list with two internal lists, because yo dawg I heard you like lists, so I got lists for your lists. (I'm gonna go end my life now for saying that)&lt;/p&gt;

&lt;p&gt;Seriously though, that's what it is. The idea is that you have two simple lists inside of the jump list. One list is the actual linked elements. The other is the true jump list. This list doesn't hold elements. Rather, its element is actually just another reference to a node. Only this time around, the node reference isn't a reference to a node in itself, but rather the other list. To facilitate knowing where you even are, this needs to additionally store either an index, or a skip amount similar to the skip list. In either case, it's another approach to rapid indexing.&lt;/p&gt;

&lt;p&gt;As far as I can tell, I independently arrived to this solution back in 2013. If you've got research showing otherwise, please send it my way.&lt;/p&gt;

&lt;h1&gt;
  
  
  S-Lists
&lt;/h1&gt;

&lt;p&gt;Gonna be straight up. I discovered this one about 5 minutes before starting this article so I really don't feel comfortable talking about it just yet. It was published as &lt;a href="http://cisjournal.org/journalofcomputing/archive/vol4no6/vol4no6_6.pdf"&gt;The S-Linked List – A Variant Of The Linked List Data Structure&lt;/a&gt; and seems to be useful for embedded scenarios.&lt;/p&gt;

</description>
      <category>datastructures</category>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Advanced Arrays</title>
      <dc:creator>Patrick Kelly</dc:creator>
      <pubDate>Sun, 27 Sep 2020 13:14:23 +0000</pubDate>
      <link>https://dev.to/entomy/advanced-arrays-50e3</link>
      <guid>https://dev.to/entomy/advanced-arrays-50e3</guid>
      <description>&lt;p&gt;Liquid syntax error: 'raw' tag was never closed&lt;/p&gt;
</description>
      <category>datastructures</category>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Collectathon</title>
      <dc:creator>Patrick Kelly</dc:creator>
      <pubDate>Sat, 26 Sep 2020 12:25:12 +0000</pubDate>
      <link>https://dev.to/entomy/collectathon-8i8</link>
      <guid>https://dev.to/entomy/collectathon-8i8</guid>
      <description>&lt;p&gt;Typically, when I talk about work I'm doing, I talk about &lt;a href="https://github.com/Stringier"&gt;&lt;strong&gt;Stringier&lt;/strong&gt;&lt;/a&gt; because I mostly deal with text processing now, and that set of libraries serves the foundation for a lot of the work I do. Over the two years of developing &lt;a href="https://github.com/Stringier"&gt;&lt;strong&gt;Stringier&lt;/strong&gt;&lt;/a&gt;, I've been increasingly implementing specialized data structures, or even just data structures that I think &lt;em&gt;should&lt;/em&gt; be in the standard library, but aren't. Sometimes, there's even the issue of the implementations just being bad, whether problematic API's or just less efficient or performant than they could be. Whenever you're doing a lot of the same thing, you've got a pattern, and you want to start looking into frameworks that aide with that pattern.&lt;/p&gt;

&lt;p&gt;So is there a framework for collections? Not really. .NET has &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.collectionbase"&gt;&lt;code&gt;CollectionBase&lt;/code&gt;&lt;/a&gt; that makes all sorts of assumptions about how your collection works and what features it supports. It's a leaky abstraction that forces your collection to behave how it says, and that's just not realistic. This may be a major factor behind why .NET doesn't have a rich tree or graph API. It may even be behind the issues with &lt;a href="https://dev.to/entomy/iset-t-considered-harmful-2hpd"&gt;&lt;code&gt;ISet&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/a&gt;. There's also &lt;a href="https://github.com/sestoft/C5"&gt;&lt;strong&gt;C5&lt;/strong&gt;&lt;/a&gt;, which isn't a bad option, but I think falls into many of the same traps that collections libraries fall into (and I've fallen for in the past, let's learn from my mistakes).&lt;/p&gt;

&lt;p&gt;This is where I starting thinking about &lt;a href="https://github.com/Entomy/Collectathon"&gt;&lt;strong&gt;Collectathon&lt;/strong&gt;&lt;/a&gt; again. &lt;a href="https://github.com/Entomy/Collectathon"&gt;&lt;strong&gt;Collectathon&lt;/strong&gt;&lt;/a&gt; was originally an attempt at designing a better collections API based on separation of Abstract Data Type and Data Structure, as well as dependency injecting certain features that were implicit whether you wanted or could even use them, like filters. There was a major goal of trying to get as much code sharing as possible, and for a while was successful at this. But then I hit a wall. A &lt;em&gt;hard&lt;/em&gt; wall. And this was the wake up I needed, and the eureka on why all collection libraries seem to have the same fundamental issue: They all make assumptions about collections that have nothing to do with that ADT because they all derive from the same core types, which by their very nature make those exact assumptions. See, collections &lt;strong&gt;don't&lt;/strong&gt; form a taxonomy. One only needs to try to implement an unsorted list, self-sorting list, and unique list ("set") from the same base type to see the issue.&lt;/p&gt;

&lt;p&gt;It wasn't until deep into the v4.0 audit and rollout of &lt;a href="https://github.com/Stringier"&gt;&lt;strong&gt;Stringier&lt;/strong&gt;&lt;/a&gt; that the solution hit me, and it hit me like a swift kick in the ass that's been allowing me to quite literally pump out several efficient collection implementations a day, even though they are drastically different ADT's, without leaking implementing details (in fact, as of this writing, &lt;a href="https://entomy.github.io/Collectathon/api/Collectathon.Traits.IResizable.html"&gt;&lt;code&gt;IResizable&lt;/code&gt;&lt;/a&gt; is the only abstraction leak). It turns out, my discovery of &lt;a href="https://dev.to/entomy/real-traits-in-c-4fpk"&gt;real traits in C#&lt;/a&gt; was critical for doing this, allowing moving sharable code outside of the types entirely, so that the hierarchy could be squashed, with no actual base type at all. In fact, the only hierarchies at all are within specific ADTs and even then they get broken when appropriate. But none of this is obvious using the trait based API.&lt;/p&gt;

&lt;p&gt;What all this means is that &lt;a href="https://github.com/Entomy/Collectathon"&gt;&lt;strong&gt;Collectathon&lt;/strong&gt;&lt;/a&gt; is two things. First, is a framework for the creation of custom collections. Second, is implementations of various collections using that framework. So, not only is it easier to provide generic collections within &lt;a href="https://github.com/Entomy/Collectathon"&gt;&lt;strong&gt;Collectathon&lt;/strong&gt;&lt;/a&gt;, but it's also easier to provide specialized collections within &lt;a href="https://github.com/Stringier"&gt;&lt;strong&gt;Stringier&lt;/strong&gt;&lt;/a&gt;. &lt;em&gt;Fantastic&lt;/em&gt;! This, by implication, means that development on &lt;a href="https://github.com/Entomy/Collectathon"&gt;&lt;strong&gt;Collectathon&lt;/strong&gt;&lt;/a&gt; is development on &lt;a href="https://github.com/Stringier"&gt;&lt;strong&gt;Stringier&lt;/strong&gt;&lt;/a&gt;, especially since the end goal is to simplify &lt;a href="https://github.com/Stringier"&gt;&lt;strong&gt;Stringier&lt;/strong&gt;&lt;/a&gt; immensely.&lt;/p&gt;

&lt;p&gt;Since the work on &lt;a href="https://github.com/Stringier"&gt;&lt;strong&gt;Stringier&lt;/strong&gt;&lt;/a&gt; is going to take quite a while, and most of the functions I'd like to talk about are in &lt;a href="https://github.com/Stringier/Core"&gt;&lt;strong&gt;Core&lt;/strong&gt;&lt;/a&gt; which requires the most work, I really can't talk about them yet. But, what I can do is talk about data structures as I implement them. This isn't just a "hey here's some basic data structures I learned about in a 30 minute data structures video" kinda series though. No. I'm gonna talk about thinks like what partial-unrolling means to a linked-list. How skip-lists can be superior to binary-trees when you know you have ordered data. What a trie or in-tree is. How a proper set is implemented and works. And more!&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>ISet&lt;T&gt; Considered Harmful</title>
      <dc:creator>Patrick Kelly</dc:creator>
      <pubDate>Thu, 24 Sep 2020 17:03:37 +0000</pubDate>
      <link>https://dev.to/entomy/iset-t-considered-harmful-2hpd</link>
      <guid>https://dev.to/entomy/iset-t-considered-harmful-2hpd</guid>
      <description>&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.iset-1"&gt;&lt;code&gt;ISet&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/a&gt; is a disaster waiting to happen, should be considered a code smell, and considered harmful. But why?&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Nanos gigantum humeris insidentes&lt;/p&gt;
&lt;/blockquote&gt;




&lt;blockquote&gt;
&lt;p&gt;If I have seen further it is by standing on the shoulders of Giants. -- Isaac Newton&lt;/p&gt;
&lt;/blockquote&gt;




&lt;blockquote&gt;
&lt;p&gt;I say with Didacus Stella, a dwarf standing on the shoulders of a giant may see farther than a giant himself. -- Diego de Estella&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;strong&gt;If&lt;/strong&gt; we reuse an existing idea, we can build upon the entire corpus of knowlege built upon it. &lt;em&gt;We can stand on giants, and see further&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So is there an existing idea and corpus we can stand upon? Yes, and it's &lt;a href="https://en.wikipedia.org/wiki/Set_theory"&gt;Set Theory&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Algebra_of_sets"&gt;Set Algebra&lt;/a&gt;. In reusing these ideas, we can build upon ever pitfall, every mistake, every advancement, and every solution people before us have found. Does &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.iset-1"&gt;&lt;code&gt;ISet&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/a&gt; do this? &lt;strong&gt;No&lt;/strong&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Where &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.iset-1"&gt;&lt;code&gt;ISet&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/a&gt; goes wrong
&lt;/h1&gt;

&lt;p&gt;Before anything else, I should probably clarify what a set is. A set is a collection where each element only exists once, and does not care about the order of the elements, nor how the internals are structured. It only cares about what is in the set. Evaluating against this alone, &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.iset-1"&gt;&lt;code&gt;ISet&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/a&gt; seems fine. But this isn't the whole picture.&lt;/p&gt;

&lt;p&gt;Sets are inherently immutable. Consider the set of all even numbers. There's no reason to add a new number to the set, for the set &lt;em&gt;always&lt;/em&gt; contained all even numbers. So why does &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.iset-1"&gt;&lt;code&gt;ISet&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/a&gt; provide &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.iset-1.add"&gt;&lt;code&gt;Add()&lt;/code&gt;&lt;/a&gt;? Is this problematic? Consider:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;ISet&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;evens&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;HashSet&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;8.&lt;/span&gt;&lt;span class="p"&gt;..});&lt;/span&gt;
&lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;False&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;evens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// passes&lt;/span&gt;
&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;evens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;False&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;evens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// fails&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Whoa, wait, why is this allowable? We just violated the semantics of the set!&lt;/p&gt;

&lt;p&gt;But this isn't the only place where we can violate set semantics. Oh no.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;ISet&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;primaryColors&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;HashSet&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Red&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Yellow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Blue&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="n"&gt;ISet&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;printerColors&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;HashSet&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cyan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Magenta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Yellow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Black&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="n"&gt;primaryColors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UnionWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;printerColors&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;False&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;primaryColors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Magenta&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// fails&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Magenta isn't a primary color! Why did this happen? One only needs to look at the signature and summary of &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.iset-1.unionwith"&gt;&lt;code&gt;UnionWith()&lt;/code&gt;&lt;/a&gt; to see why.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;UnionWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;other&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;Modifies the current set so that it contains all elements that are present in the current set, in the specified collection, or in both.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This isn't even the end of the story though. &lt;a href="https://en.wikipedia.org/wiki/Algebra_of_sets"&gt;Set Algebra&lt;/a&gt;, much like the &lt;a href="https://en.wikipedia.org/wiki/Abstract_algebra"&gt;Abstract Algebra&lt;/a&gt; you're familiar with from &lt;a href="https://en.wikipedia.org/wiki/Algebraic_number_theory"&gt;Algebraic Number Theory&lt;/a&gt; has the concept of identities that are very important for its operation. These are empty set (Ø) and universe set (U). Trying to do set algebra without identities is like trying to do abstract algebra without 0 and 1!&lt;/p&gt;

&lt;p&gt;Furthermore, &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.iset-1"&gt;&lt;code&gt;ISet&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/a&gt; is a &lt;a href="https://en.wikipedia.org/wiki/Leaky_abstraction"&gt;leaky abstraction&lt;/a&gt;, and this isn't just a case of a code smell where it makes it difficult to do refactorings later on, although that is a problem in and of itself. Because of the implementation details leaking through, we know &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.iset-1"&gt;&lt;code&gt;ISet&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/a&gt; is a collection like any other. What's wrong with that? The problem is immediately apparent with the &lt;a href="https://en.wikipedia.org/wiki/Complement_(set_theory)"&gt;compliment&lt;/a&gt; operation. Consider the compliment of all primary colors. This is a set that has to contain &lt;em&gt;every&lt;/em&gt; color that is not one of the three primary colors. You're guaranteed to run out of memory! There's infinite colors! Even if we were to just go with 24-bit colors that computers can represent, even though some advanced color spaces use even larger amounts, this means allocating &lt;code&gt;16,777,216 - 3&lt;/code&gt; color structures, at 32-bits each, for &lt;code&gt;536,870,816&lt;/code&gt; bits or &lt;code&gt;67,108,852&lt;/code&gt; bytes of memory! I don't know about you, but I don't have a computer that can hold that.&lt;/p&gt;

&lt;h1&gt;
  
  
  What &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.iset-1"&gt;&lt;code&gt;ISet&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/a&gt; should be
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.iset-1"&gt;&lt;code&gt;ISet&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/a&gt;'s problems stem from deriving from &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.icollection-1"&gt;&lt;code&gt;ICollection&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/a&gt; which itself is problematic because it makes incorrect assumptions about what is common amongst all collections. Sets are only one of the areas where those assumptions are violated.&lt;/p&gt;

&lt;p&gt;Instead, sets should adhere as closely to the established &lt;a href="https://en.wikipedia.org/wiki/Set_theory"&gt;Set Theory&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Algebra_of_sets"&gt;Set Algebra&lt;/a&gt; as possible. This not only ensures that basic semantics of a set are as they should be, but also that discovered and published solutions which utilize &lt;a href="https://en.wikipedia.org/wiki/Set_theory"&gt;Set Theory&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Algebra_of_sets"&gt;Set Algebra&lt;/a&gt; can be readily adopted by programmers facing difficult problems, rather than working out new solutions using an ad-hoc theory and ad-hoc algebra likely rife with undiscovered problems.&lt;/p&gt;

&lt;p&gt;I've been doing exactly this inside of &lt;a href="https://github.com/Entomy/Collectathon"&gt;&lt;strong&gt;Collectathon&lt;/strong&gt;&lt;/a&gt;, a project I revived earlier this month (Sept, 2020). As of this article the resulting code hasn't been committed just yet, as I'm fleshing out expected algebraic operations, but the implementation and interface have been delightful, and actually rather simple. Furthermore, as I talked about in a previous article, &lt;a href="https://dev.to/entomy/category-class-1602"&gt;&lt;code&gt;Category&lt;/code&gt;&lt;/a&gt; was conceptually a set as well, and in implementing a generalized set base, the implementation of &lt;a href="https://dev.to/entomy/category-class-1602"&gt;&lt;code&gt;Category&lt;/code&gt;&lt;/a&gt; can be simplified, with the entirety of set algebra automatically provided, by simply deriving from &lt;code&gt;Set&lt;/code&gt;. That is a fantastic example of code reuse.&lt;/p&gt;

&lt;p&gt;Again:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If I have seen further it is by standing on the shoulders of Giants. -- Isaac Newton&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>computerscience</category>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
  </channel>
</rss>
