A C# library to write functional code - Part IV - Type Unions - Luca Bolognese

A C# library to write functional code - Part IV - Type Unions

Luca -

☕ 2 min. read

Other posts in the se­ries:

  • Part I - Background
    • Part II - Tuples

      A bunch of you wrote telling me to fin­ish this. So here I go: let’s talk about type unions. First of all: they are not called like that. The cor­rect name is dis­crim­i­nated unions. I have no idea why I call them dif­fer­ently, but I want to be con­sis­tent with my pre­vi­ous mis­take.

      For those of you with a C++ back­ground (like my­self) they are like unions, just bet­ter (or worse de­pend­ing on your con­vic­tions). They let you de­fine a type that can rep­re­sent one of sev­eral dif­fer­ent types. You can then use the match’ op­er­a­tor (discussed in the next post) to pat­tern match against it.

      I won’t elab­o­rate on the pros and cons of this style of pro­gram­ming ver­sus us­ing poly­mor­phism. I just want to show you how I im­ple­mented this con­struct in C#. As al­ways, my usual caveat: this is just educational code’, use it at your own risk, no ex­ten­sive or perf re­lated test has been done on it. You can down­load the zip file and check my unit tests for your­self.

      How type unions are used

      In my world, you de­clare a type union like this:

      public class Person { }
      

pub­lic class Dog { } pub­lic class Friend : TypeUnion<Person, Dog> { pub­lic Friend(Person p) : base§ { } pub­lic Friend(Dog d) : base(d) { } }

    You inherit a type union from the TypeUnion class and use generic parameters that correspond to the types that the union can represent.
    
    You can then create a type union as:
    
    <pre class="code"><span style="color:blue;">var </span>fr = <span style="color:blue;">new </span><span style="color:#2b91af;">Friend</span>(<span style="color:blue;">new </span><span style="color:#2b91af;">Dog</span>());</pre>
    
    Test its type by:
    
    <pre class="code"><span style="color:#2b91af;">Assert</span>.IsTrue(fr.Is&lt;<span style="color:#2b91af;">Dog</span>&gt;());

Assert.IsFalse(fr.Is<Person>());

    Cast it to one of the types they represent:
    
    <pre class="code"><span style="color:blue;">var </span>d = fr.As&lt;<span style="color:#2b91af;">Dog</span>&gt;();</pre>
    
    Or use it with the &#8216;match' operator (fully explained in an upcoming post):
    
    <pre class="code"><span style="color:blue;">var </span>r = <span style="color:#2b91af;">F</span>.Match(fr,
f =&gt; f.Is&lt;<span style="color:#2b91af;">Dog</span>&gt;(), f =&gt; f.As&lt;<span style="color:#2b91af;">Dog</span>&gt;().ToString(),
f =&gt; f.Is&lt;<span style="color:#2b91af;">Person</span>&gt;(), f =&gt; f.As&lt;<span style="color:#2b91af;">Person</span>&gt;().ToString());

Assert.AreEqual(r, new Dog().ToString());

    Or the slightly more pleasing:
    
    <pre class="code">r = <span style="color:#2b91af;">F</span>.Match(fr,
        (<span style="color:#2b91af;">Person </span>p) =&gt; p.ToString(),
        (<span style="color:#2b91af;">Dog </span>d) =&gt; d.ToString());

Assert.AreEqual(r, new Dog().ToString());

    You get the idea.
    
    **How they are implemented**
    
    Nothing really sophisticated going on here. Let's take as an example a type union that can represent two types. I have versions that go to 5 types in the zip file.
    
    First of all a TypeUnion is a Record:
    
    <pre class="code"><span style="color:blue;">public class </span><span style="color:#2b91af;">TypeUnion</span>&lt;T1, T2&gt; : <span style="color:#2b91af;">Record</span>&lt;T1, T2&gt; {</pre>
    
    It has overloaded constructors to create a type union of a particular type:
    
    <pre class="code"><span style="color:blue;">public </span>TypeUnion(T1 t1)
: <span style="color:blue;">base</span>(t1, <span style="color:blue;">default</span>(T2)) {
UnionType = t1.GetType();

} pub­lic TypeUnion(T2 t2) : base(de­fault(T1), t2) { UnionType = t2.Get­Type(); }

    UnionType is used to &#8216;remember' which type it is:
    
    <pre class="code"><span style="color:blue;">protected </span><span style="color:#2b91af;">Type </span>UnionType;</pre>
    
    It also has properties to return the objects of all the types that can be stored:
    
    <pre class="code"><span style="color:blue;">protected </span>T1 Type1 { <span style="color:blue;">get </span>{ <span style="color:blue;">return </span>state.Item1; } }

pro­tected T2 Type2 { get { re­turn state.Item2; } }

    The &#8216;Is' operator is simply implemented as:
    
    <pre class="code"><span style="color:blue;">public bool </span>Is&lt;K&gt;() {
<span style="color:blue;">return typeof</span>(K).IsAssignableFrom(UnionType);

}

    And the &#8216;As' operator looks like so:
    
    <pre class="code"><span style="color:blue;">public </span>K As&lt;K&gt;() {
<span style="color:blue;">if </span>(!Is&lt;K&gt;())
    <span style="color:blue;">throw new </span><span style="color:#2b91af;">Exception</span>(<span style="color:blue;">string</span>.Format(<br />          <span style="color:#a31515;">"In a TypeUnion cannot cast from {0} to {1}"</span>,<br />          UnionType.Name, <span style="color:blue;">typeof</span>(K).Name));
<span style="color:blue;">if </span>(<span style="color:blue;">typeof</span>(T1) == UnionType)
    <span style="color:blue;">return </span>(K)(<span style="color:blue;">object</span>) Type1;
<span style="color:blue;">if </span>(<span style="color:blue;">typeof</span>(T2) == UnionType)
    <span style="color:blue;">return </span>(K)(<span style="color:blue;">object</span>) Type2;
<span style="color:blue;">throw new </span><span style="color:#2b91af;">Exception</span>(<span style="color:#a31515;">"Shouldn't get here"</span>);

}

    I leave as an exercise to the reader to understand what happens if T1 and T2 are the same type or inherit from the same type. I could have written code to handle this case in a more explicit manner, but didn't.
    
    Also, by reviewing my code I found an obvious bug in my Is<K>/As<K> code. I fixed it and re-posted the zip file in the second post of this series.
    
    Now back to the beach. Next post is on the &#8216;match' operator.
10 Comments

Comments

I'm curious as why you chose to inherit from Record as opposed to using it as a member variable.  From your example it doesn't look like a TypeUnion "is" a Record so much as it uses a Record.  

I cannot recall the reason, if there ever was one.
On the face of it, you are right.

configurator

2008-06-09T18:35:32Z

To access the type union you use the Is and As operator. That means that the usage of Type1 and Type2 in the record is not needed.
You can simply keep the value in a member object-type field. Then, you would simplify the code of As<> and not really much change anything else - except the constantly unused memory slot.
Also, you would be more efficient because the cast to object would be unnecessary. The only two things that would enforce or use the given types would be the constructor - which would only use the given types - and the match operator.
Just my two pence.

hi
very nice your teachinfg methosd pls sent all C# programming learn tools
Thank You

How can it be useful?! Does anybody have a real-world example?

Strange Cat

2008-06-25T10:36:42Z

Good to know lots of italian work for Microsoft :)
Ciao

Hasan Naqvi

2008-06-27T08:15:18Z

nice but wud u please tell us the usage of type unions in real world scenerios.

Humberto Moreno

2008-06-30T11:00:46Z

I think it would be a good idea to extend the base class to support not just two types, but multiple types. - Btw. I agree with Jared Parsons suggestion.
Overall it's a good idea. Thanks

Luca Bolognese's WebLog

2008-07-15T05:46:25Z

Other posts in the series: Part I - Background Part II - Tuples Part III - Records Part IV - Type Unions

0 Webmentions

These are webmentions via the IndieWeb and webmention.io.