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

-

Other posts in the se­ries:

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.

Tags

10 Comments

Comments

I’m cu­ri­ous as why you chose to in­herit from Record as op­posed to us­ing it as a mem­ber vari­able.  From your ex­am­ple it does­n’t look like a TypeUnion is” a Record so much as it uses a Record.  

I can­not re­call the rea­son, if there ever was one.
On the face of it, you are right.

configurator

2008-06-09T18:35:32Z

To ac­cess the type union you use the Is and As op­er­a­tor. That means that the us­age of Type1 and Type2 in the record is not needed.
You can sim­ply keep the value in a mem­ber ob­ject-type field. Then, you would sim­plify the code of As<> and not re­ally much change any­thing else - ex­cept the con­stantly un­used mem­ory slot.
Also, you would be more ef­fi­cient be­cause the cast to ob­ject would be un­nec­es­sary. The only two things that would en­force or use the given types would be the con­struc­tor - which would only use the given types - and the match op­er­a­tor.
Just my two pence.

hi
very nice your teach­infg methosd pls sent all C# pro­gram­ming learn tools
Thank You

How can it be use­ful?! Does any­body have a real-world ex­am­ple?

Strange Cat

2008-06-25T10:36:42Z

Good to know lots of ital­ian work for Microsoft :)
Ciao

Hasan Naqvi

2008-06-27T08:15:18Z

nice but wud u please tell us the us­age of type unions in real world scene­r­ios.

Humberto Moreno

2008-06-30T11:00:46Z

I think it would be a good idea to ex­tend the base class to sup­port not just two types, but mul­ti­ple types. - Btw. I agree with Jared Parsons sug­ges­tion.
Overall it’s a good idea. Thanks

Luca Bolognese's WebLog

2008-07-15T05:46:25Z

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