2008/06/06 ~~ Offline ~~ Menu

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


Other posts in the series:

public class Dog { } public class Friend : TypeUnion<Person, Dog> { public Friend(Person p) : base(p) { } public 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();

} public TypeUnion(T2 t2) : base(default(T1), t2) { UnionType = t2.GetType(); }

    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; } }

protected T2 Type2 { get { return 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.
Top