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


Other posts in the series:


  • Part I – Background
  • Part II – Tuples
  • Part III – Records

  • Part IV – Type Unions

  • Part V – The Match operator

  • I’m sorry for my prolonged absence in the middle of this series of posts. I’m on a long paternity leave in Italy (playing beach volley every day). It’s hard to have the discipline …


    A bunch of you wrote telling me to finish this. So here I go: let’s talk about type unions. First of all: they are not called like that. The correct name is discriminated unions. I have no idea why I call them differently, but I want to be consistent with my previous mistake.


    For those of you with a C++ background (like myself) they are like unions, just better (or worse depending on your convictions). They let you define a type that can represent one of several different types. You can then use the ‘match’ operator (discussed in the next post) to pattern match against it.


    I won’t elaborate on the pros and cons of this style of programming versus using polymorphism. I just want to show you how I implemented this construct in C#. As always, my usual caveat: this is just ‘educational code’, use it at your own risk, no extensive or perf related test has been done on it. You can download the zip file and check my unit tests for yourself.


    How type unions are used


    In my world, you declare a type union like this:

    public class Person { }
    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:

    var fr = new Friend(new Dog());

    Test its type by:

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

    Cast it to one of the types they represent:

    var d = fr.As<Dog>();

    Or use it with the ‘match’ operator (fully explained in an upcoming post):

    var r = F.Match(fr,
    f => f.Is<Dog>(), f => f.As<Dog>().ToString(),
    f => f.Is<Person>(), f => f.As<Person>().ToString());

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


    Or the slightly more pleasing:

    r = F.Match(fr,
    (Person p) => p.ToString(),
    (Dog d) => 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:

    public class TypeUnion<T1, T2> : Record<T1, T2> {

    It has overloaded constructors to create a type union of a particular type:

    public TypeUnion(T1 t1)
    : base(t1, default(T2)) {

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

    UnionType = t2.GetType();
    }


    UnionType is used to ‘remember’ which type it is:

    protected Type UnionType;

    It also has properties to return the objects of all the types that can be stored:

    protected T1 Type1 { get { return state.Item1; } }
    protected T2 Type2 { get { return state.Item2; } }

    The ‘Is’ operator is simply implemented as:

    public bool Is<K>() {

    return typeof(K).IsAssignableFrom(UnionType);
    }


    And the ‘As’ operator looks like so:

    public K As<K>() {

    if (!Is<K>())
    throw new Exception(string.Format(
    “In a TypeUnion cannot cast from {0} to {1}”,
    UnionType.Name, typeof(K).Name));

    if (typeof(T1) == UnionType)
    return (K)(object) Type1;
    if (typeof(T2) == UnionType)
    return (K)(object) Type2;

    throw new Exception(“Shouldn’t get here”);
    }


    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 ‘match’ operator.

    Comments (10)

    1. 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.  

    2. lucabol says:

      I cannot recall the reason, if there ever was one.

      On the face of it, you are right.

    3. configurator says:

      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.

    4. santhiran says:

      hi

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

      Thank You

    5. Coder says:

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

    6. Strange Cat says:

      Good to know lots of italian work for Microsoft 🙂

      Ciao

    7. Hasan Naqvi says:

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

    8. Humberto Moreno says:

      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

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

    Skip to main content