A C# library to write functional code - Part II - Tuples - Luca Bolognese

A C# library to write functional code - Part II - Tuples

Luca -

☕ 4 min. read

Other posts in the se­ries:

  • Part I - Background
    • Part II - Tuples

      There is a strange asym­me­try in main­stream OO lan­guages in that you can pass mul­ti­ple pa­ra­me­ters to a func­tion, but you can re­turn just one value. Granted, there are ways around it: you can use ref’ in C# or re­turn some sort of col­lec­tion where things are stored. But by and large the model is: you pass many, you get one; if you need to re­turn more than one, cre­ate a class to rep­re­sent this bunch of data’. Tuples are a way for you not to cre­ate such a class.

      Tuples are also much more than that. Once you have the lan­guage con­cept of a bunch of data with­out a name’, you can cre­ate ar­rays of them, you can pass them as pa­ra­me­ters, use them as lo­cal vari­ables. Wherever you’d use a type, you can use a Tuple in­stead.

      This is par­tic­u­larly ap­peal­ing to me as I like to use classes al­most ex­clu­sively to rep­re­sent things that have a coun­ter­part in the do­main I’m mod­el­ing (i.e. Customer, Account). I don’t like to cre­ate classes/​structs just for the sake of tem­porar­ily put some data to­gether.

      You can cre­ate your own Tuple class in C#, but the syn­tax gets ugly. Syntax mat­ter. Syntax helps you to think dif­fer­ently about your pro­gram. We have syn­tax for anony­mous types, but given that they can­not es­cape the scope of a method, they can­not be used as full re­place­ment for Tuples.

      In any case, to my im­ple­men­ta­tion. Here is how you cre­ate a Tuple:

      var t1 = F.Tuple(34, "bo", 2.3);

      not too bad. In F# it is bet­ter: (34, bo, 2.3). And you of­ten don’t need the paren­the­sis. But still, my C# ver­sion is ok.

      You then need to ac­cess its el­e­ments:

      var n = t1.Item1;
          var s = t1.Item2;
      
    In F# you usually access them by doing pattern matching, which gives a more intuitive syntax. But again, my C# syntax is not terrible. 
    
    Tuples need to have structural equality, which means that the following has to work:
    
    <pre class="code"><span style="color:rgb(43,145,175);">ArrayList</span> mad1 = <span style="color:rgb(0,0,255);">new</span> <span style="color:rgb(43,145,175);">ArrayList</span> { <span style="color:rgb(0,0,255);">new</span> <span style="color:rgb(43,145,175);">List</span>&lt;<span style="color:rgb(43,145,175);">IEnumerable</span>&lt;<span style="color:rgb(0,0,255);">string</span>&gt;&gt; { <span style="color:rgb(0,0,255);">new</span> <span style="color:rgb(0,0,255);">string</span>[] { <span style="color:rgb(163,21,21);">"bo"</span> }, <span style="color:rgb(0,0,255);">new</span> <span style="color:rgb(0,0,255);">string</span>[] { <span style="color:rgb(163,21,21);">"bo"</span> } },<br />                               32, <span style="color:rgb(163,21,21);">"bo"</span>, <span style="color:rgb(0,0,255);">new</span> <span style="color:rgb(0,0,255);">int</span>[] { 4, 5, 6 } };
    <span style="color:rgb(43,145,175);">ArrayList</span> mad2 = <span style="color:rgb(0,0,255);">new</span> <span style="color:rgb(43,145,175);">ArrayList</span> { <span style="color:rgb(0,0,255);">new</span> <span style="color:rgb(43,145,175);">List</span>&lt;<span style="color:rgb(43,145,175);">IEnumerable</span>&lt;<span style="color:rgb(0,0,255);">string</span>&gt;&gt; { <span style="color:rgb(0,0,255);">new</span> <span style="color:rgb(0,0,255);">string</span>[] { <span style="color:rgb(163,21,21);">"bo"</span> }, <span style="color:rgb(0,0,255);">new</span> <span style="color:rgb(0,0,255);">string</span>[] { <span style="color:rgb(163,21,21);">"bo"</span> } },<br />                               32, <span style="color:rgb(163,21,21);">"bo"</span>, <span style="color:rgb(0,0,255);">new</span> <span style="color:rgb(0,0,255);">int</span>[] { 4, 5, 6 } };
    <span style="color:rgb(43,145,175);">ArrayList</span> mad3 = <span style="color:rgb(0,0,255);">new</span> <span style="color:rgb(43,145,175);">ArrayList</span> { <span style="color:rgb(0,0,255);">new</span> <span style="color:rgb(43,145,175);">List</span>&lt;<span style="color:rgb(43,145,175);">IEnumerable</span>&lt;<span style="color:rgb(0,0,255);">string</span>&gt;&gt; { <span style="color:rgb(0,0,255);">new</span> <span style="color:rgb(0,0,255);">string</span>[] { <span style="color:rgb(163,21,21);">"bo"</span> }, <span style="color:rgb(0,0,255);">new</span> <span style="color:rgb(0,0,255);">string</span>[] { <span style="color:rgb(163,21,21);">"bo"</span> } },<br />                               32, <span style="color:rgb(163,21,21);">"bo"</span>, <span style="color:rgb(0,0,255);">new</span> <span style="color:rgb(0,0,255);">int</span>[] { 4, 5, 5 } };</pre>
    
    
    
    <pre class="code"><span style="color:rgb(43,145,175);">Assert</span>.AreEqual(<span style="color:rgb(43,145,175);">F</span>.Tuple(mad1, mad2, mad1), <span style="color:rgb(43,145,175);">F</span>.Tuple(mad2, mad1, mad2));
    <span style="color:rgb(43,145,175);">Assert</span>.AreNotEqual(<span style="color:rgb(43,145,175);">F</span>.Tuple(mad1, mad2, mad1), <span style="color:rgb(43,145,175);">F</span>.Tuple(mad1, mad3, mad1));</pre>
    
    You can use Tuples as return values, parameters, locals etc. Unfortunately, the syntax is ugly when Tuples are part of the signature of a function:
    
    <pre class="code"><span style="color:rgb(0,0,255);">public</span> <span style="color:rgb(43,145,175);">Tuple</span>&lt;<span style="color:rgb(0,0,255);">string</span>, <span style="color:rgb(43,145,175);">IEnumerable</span>&lt;<span style="color:rgb(43,145,175);">Tuple</span>&lt;<span style="color:rgb(0,0,255);">string</span>, <span style="color:rgb(43,145,175);">ObservationHistory</span>&gt;&gt;&gt; Execute() {
}</pre>
    
    With the above information, you can be a user of Tuples. From this point on, I'll talk about some details of the implementation (I also attach the full code to this post as a zip file).
    
    <pre class="code"><span style="color:rgb(0,0,255);">public</span> <span style="color:rgb(0,0,255);">class</span> <span style="color:rgb(43,145,175);">Tuple</span>&lt;T1&gt; {
    <span style="color:rgb(0,0,255);">public</span> Tuple(T1 t1) {
        Item1 = t1;
    }
    <span style="color:rgb(0,0,255);">public</span> <span style="color:rgb(0,0,255);">readonly</span> T1 Item1;

#region Equals, GetHashCode, ==, != } pub­lic class Tuple<T1, T2> : Tuple<T1> { pub­lic Tuple(T1 t1, T2 t2) : base(t1) { Item2 = t2; } pub­lic read­only T2 Item2; #region Equals, GetHashCode, ==, != }

    &nbsp;
    
    So, Tuples are classes, not structs. The reason for it is fully described in <a href="http://blogs.msdn.com/lucabol/archive/2008/01/11/creating-an-immutable-value-object-in-c-part-v-using-a-library.aspx" target="_blank"><strong><font color="#006bad">this series of posts</font></strong></a>. They also inherit from one another. There are pros and cons to that. The main pros are that I had to write less code and that you can pass a Tuple<int, string> when a function expects a Tuple<int, string, int>. The main drawback is that you can pass a Tuple<int, string> when a function expects a Tuple<int, string, int>.&nbsp; Also notice the use of public fields. These&nbsp;is a problem with frameworks that insist on properties (i.e. Data Binding). Also, I just got to 5 as arity goes. The day I need 6 items, I'll add another one. It is boilerplate code (that I'd still like not to write).
    
    The Equals method is a bit convoluted:
    
    <pre class="code"><span style="color:rgb(0,0,255);">internal</span> <span style="color:rgb(0,0,255);">static</span> <span style="color:rgb(0,0,255);">class</span> <span style="color:rgb(43,145,175);">Utils</span> {
    <span style="color:rgb(0,0,255);">public</span> <span style="color:rgb(0,0,255);">static</span> <span style="color:rgb(0,0,255);">void</span> CheckNull&lt;T&gt;(T t) {
        <span style="color:rgb(0,0,255);">if</span> (t == <span style="color:rgb(0,0,255);">null</span>)
            <span style="color:rgb(0,0,255);">throw</span> <span style="color:rgb(0,0,255);">new</span> <span style="color:rgb(43,145,175);">ArgumentNullException</span>();
    }<br />     }</pre>
    
    
    
    <pre class="code"><span style="color:rgb(0,0,255);">public</span> <span style="color:rgb(0,0,255);">override</span> <span style="color:rgb(0,0,255);">bool</span> Equals(<span style="color:rgb(0,0,255);">object</span> right) {
        <span style="color:rgb(43,145,175);">Utils</span>.CheckNull(right);
        <span style="color:rgb(0,0,255);">if</span> (<span style="color:rgb(0,0,255);">object</span>.ReferenceEquals(<span style="color:rgb(0,0,255);">this</span>, right))
            <span style="color:rgb(0,0,255);">return</span> <span style="color:rgb(0,0,255);">true</span>;
        <span style="color:rgb(0,0,255);">if</span> (<span style="color:rgb(0,0,255);">this</span>.GetType() != right.GetType())
            <span style="color:rgb(0,0,255);">return</span> <span style="color:rgb(0,0,255);">false</span>;
        <span style="color:rgb(0,0,255);">var</span> rightT = right <span style="color:rgb(0,0,255);">as</span> <span style="color:rgb(43,145,175);">Tuple</span>&lt;T1, T2, T3&gt;;
        <span style="color:rgb(0,0,255);">return</span> <span style="color:rgb(0,0,255);">base</span>.Equals(rightT) && <span style="color:rgb(43,145,175);">F</span>.DSEquals(<span style="color:rgb(0,0,255);">this</span>.Item3, rightT.Item3);
    }</pre>
    
    
    
    I always get complaints when I show Equals methods that throw if null is passed in, but I stand by my logic, that&nbsp;the presence of null for these categories of&nbsp;&#8216;structurally equal' classes is symptom of an error and I want to be notified.&nbsp;Returning false doesn't do that.
    
    <pre class="code"><span style="color:rgb(0,0,255);">internal</span> <span style="color:rgb(0,0,255);">static</span> <span style="color:rgb(0,0,255);">bool</span> DSEquals&lt;T&gt;(T left, T right) {
        <span style="color:rgb(0,0,255);">if</span> (left == <span style="color:rgb(0,0,255);">null</span> && right == <span style="color:rgb(0,0,255);">null</span>)
            <span style="color:rgb(0,0,255);">return</span> <span style="color:rgb(0,0,255);">true</span>;
        <span style="color:rgb(0,0,255);">if</span> (left == <span style="color:rgb(0,0,255);">null</span> && right != <span style="color:rgb(0,0,255);">null</span>)
            <span style="color:rgb(0,0,255);">return</span> <span style="color:rgb(0,0,255);">false</span>;
        <span style="color:rgb(0,0,255);">var</span> len = left <span style="color:rgb(0,0,255);">as</span> <span style="color:rgb(43,145,175);">IEnumerable</span>;
        <span style="color:rgb(0,0,255);">var</span> ren = right <span style="color:rgb(0,0,255);">as</span> <span style="color:rgb(43,145,175);">IEnumerable</span>;
        <span style="color:rgb(0,0,255);">if</span> (len == <span style="color:rgb(0,0,255);">null</span> && ren == <span style="color:rgb(0,0,255);">null</span>)
            <span style="color:rgb(0,0,255);">return</span> left.Equals(right);
        <span style="color:rgb(0,0,255);">if</span> (len == <span style="color:rgb(0,0,255);">null</span> && ren != <span style="color:rgb(0,0,255);">null</span>)
            <span style="color:rgb(0,0,255);">return</span> <span style="color:rgb(0,0,255);">false</span>;
        <span style="color:rgb(0,0,255);">if</span> (len != <span style="color:rgb(0,0,255);">null</span> && ren == <span style="color:rgb(0,0,255);">null</span>)
            <span style="color:rgb(0,0,255);">return</span> <span style="color:rgb(0,0,255);">false</span>;
        <span style="color:rgb(0,0,255);">return</span> SequenceEqual(len, ren);
    }</pre>
    
    DSEquals check the content of the Tuple and forward to SequenceEqual in case one slot of the Tuple contains an IEnumerable.
    
    <pre class="code"><span style="color:rgb(0,0,255);">internal</span> <span style="color:rgb(0,0,255);">static</span> <span style="color:rgb(0,0,255);">bool</span> SequenceEqual(<span style="color:rgb(43,145,175);">IEnumerable</span> en1, <span style="color:rgb(43,145,175);">IEnumerable</span> en2) {
        <span style="color:rgb(0,0,255);">var</span> enumerator = en2.GetEnumerator();
        <span style="color:rgb(0,0,255);">foreach</span> (<span style="color:rgb(0,0,255);">var</span> o <span style="color:rgb(0,0,255);">in</span> en1) {
            <span style="color:rgb(0,0,255);">if</span> (!enumerator.MoveNext())
                <span style="color:rgb(0,0,255);">return</span> <span style="color:rgb(0,0,255);">false</span>;
            <span style="color:rgb(0,0,255);">if</span> (!DSEquals(o, enumerator.Current))
                <span style="color:rgb(0,0,255);">return</span> <span style="color:rgb(0,0,255);">false</span>;
        }
    SequenceEqual checks that the number of items in the enumerator is the same and recursively calls DSEqual to check structural equality for items at the same index in the two enumerators.
    
    GetHashCode is trivial (and maybe trivially wrong, one of these days I'll learn everything about GetHashCode() ).
    
    <pre class="code"><span style="color:rgb(0,0,255);">public</span> <span style="color:rgb(0,0,255);">override</span> <span style="color:rgb(0,0,255);">int</span> GetHashCode() {
        <span style="color:rgb(0,0,255);">return</span> <span style="color:rgb(0,0,255);">base</span>.GetHashCode() | Item3.GetHashCode();
    }</pre>
    
    
    
    The equality operators are equally simple.
    
    <pre class="code"><span style="color:rgb(0,0,255);">public</span> <span style="color:rgb(0,0,255);">static</span> <span style="color:rgb(0,0,255);">bool</span> <span style="color:rgb(0,0,255);">operator</span> ==(<span style="color:rgb(43,145,175);">Tuple</span>&lt;T1, T2, T3&gt; t1, <span style="color:rgb(43,145,175);">Tuple</span>&lt;T1, T2, T3&gt; t2) {
        <span style="color:rgb(43,145,175);">Utils</span>.CheckNull(t1);
        <span style="color:rgb(43,145,175);">Utils</span>.CheckNull(t2);
        <span style="color:rgb(0,0,255);">return</span> t1.Equals(t2);
    }
    <span style="color:rgb(0,0,255);">public</span> <span style="color:rgb(0,0,255);">static</span> <span style="color:rgb(0,0,255);">bool</span> <span style="color:rgb(0,0,255);">operator</span> !=(<span style="color:rgb(43,145,175);">Tuple</span>&lt;T1, T2, T3&gt; t1, <span style="color:rgb(43,145,175);">Tuple</span>&lt;T1, T2, T3&gt; t2) {
        <span style="color:rgb(0,0,255);">return</span> !(t1 == t2);
    }</pre>
    
    And ToString() prints my favorite Tuple format.
    
    <pre class="code"><span style="color:rgb(0,0,255);">public</span> <span style="color:rgb(0,0,255);">override</span> <span style="color:rgb(0,0,255);">string</span> ToString() {
        <span style="color:rgb(0,0,255);">return</span> <span style="color:rgb(0,0,255);">string</span>.Format(<span style="color:rgb(163,21,21);">"{0},{1}"</span>, <span style="color:rgb(0,0,255);">base</span>.ToString(), Item3.ToString());
    }</pre>
    
    I'm sure you can find plenty of issues in this code. As always, it is not &#8216;production ready', it is more &#8216;Luca having fun doing it'. In any case, there are some testcases in the solution to check the extent of my testing.
    
    In the next post we'll look at Records.
    
    [Functional.zip](https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Components.PostAttachments/00/08/36/99/78/Functional.zip)
16 Comments

Comments

What about:
internal static bool DSEquals<T>(T left, T right) {
   if (left == null && right == null)
       return true;
   if (left == null && right != null)
       return false;
   var len = left as IEnumerable;
   var ren = right as IEnumerable;
   if (len == null && ren == null)
       return left.Equals(right);
   if (len != null && ren != null)
       return SequenceEqual(len, ren);
   return false;
}

Adam Cooper

2008-04-16T09:47:44Z

Luca,
Thanks so much for sharing this, both your posts and the source code.
I really like your idea of bringing some (more) of F#'s goodness to C#. I spent some time investigating if F# was the right tool for some of our company projects and, while I think F# is fantastic, our domain is one of storing and retrieving lots of hierarchical data, a domain which is ideal for an object-oriented language like C#. So C# is the clear choice for us (in the vast majority of cases). However, there are quite a few aspects of functional programming I'm really beginning to admire.
I've never been happy with the OO paradigm of many-inputs-one-output, and I find your Tuples solution exciting. Can you comment on how your Tuples implementation differs from anonymous types in C#?
Thanks and keep up the good work,
Adam Cooper

Thanks for the kind words.
There are two differences:
1. Anonymous types allow you to give a name to each property, while tuple don't.
2. You cannot return anonymous types from methods or passing them as parameters. So their used is limited to the body of a method.
Overall anonymous types are a mix of tuples and records. I'll talk about records in an upcoming post.

Luca Bolognese's WebLog

2008-04-21T13:35:42Z

Previous posts: Part I - Background Part II - Tuples Now that we know what Tuples are, we can start talking

Charlie Calvert's Community Bl

2008-04-23T16:58:14Z

Welcome to the forty-third issue of Community Convergence. The last few weeks have been consumed by the

Configurator

2008-04-24T04:12:14Z

I'm wondering: Doesn't CheckNull cause an infinite loop?
Usually when checking null, I would use ReferenceEquals(t, null) because == would call the type's operator ==, which checks for null causing an infinite loop.
If CheckNull accepted an object and wasn't generic, if would use object's ==, which works for null. But since it's generic it should use the == that you supplied.
Am I missing something here?

Eamon Nerbonne

2008-04-24T05:04:04Z

I've also needed to build these things, and have also run into some of the same issues you seem to have here - like the surprising unhandiness of structs (and even more surprising slowness).
Incidentally, your hash-code is no good.  You don't want to use a symmetric combination of two hash codes, since that means that F.Tuple(true,false) is equal to F.Tuple(false, true) in terms of hashcode.  A non-symmetric combination is probably best; but the instantly obvious subtraction is definitely not a good idea, since that means that all tuples of two elements with identical members have a hash-code of 0.
I choose to scale the hashcode with a prime number.  Trial and error on my test-set (consisting of lower-case strings which may not be representative for others) found that 137 is fine; so that's what I use, but I haven't researched the issue.
Further, if your tuples will be used extensively in things like lookup tables, then hash-code calculation becomes relevant:  you might want to store the hashcode once and reuse it (which can also help speed up equality comparisons when these are performed outside of a hash table).

It doesn't go into an infinite loop because it is generic. We cannot call the overload == because at that point in the code we don't know what it is. So we box it and 'compare the pointer' insted. The commented IL for the function should clarify:
.method public hidebysig static void CheckNull<T>(!!T t) cil managed
{
   .maxstack 2
   .locals init (
       [0] bool CS$4$0000)
   L_0000: nop
   L_0001: ldarg.0
   L_0002: box !!T // We box it
   L_0007: ldnull
   L_0008: ceq // We compare it
   L_000a: ldc.i4.0
   L_000b: ceq
   L_000d: stloc.0
   L_000e: ldloc.0
   L_000f: brtrue.s L_0017
   L_0011: newobj instance void [mscorlib]System.ArgumentNullException::.ctor()
   L_0016: throw
   L_0017: ret
}

Eamon: I know my hash is bad. I was too lazy to produce a better one :)

David Nelson

2008-04-28T00:42:14Z

The problem with your "this should never be null" logic is that it prevents the user from ever writing code like this:
Tuple<int, int> MyMethod()
{
  Tuple<int, int> result = null;
  // Some code which may or may not set result
  if(result == null)
  {
     // Some other code which always sets the result
  }
  return result;
}
This is a reasonably common pattern. Your code is checking for null in the wrong place. It is not unreasonable that any Tuple reference might  sometimes be null. Tuples should only be checked for null where it is sure that they should never be null.

Hi David,
I used this code to learn functional programming. In that style variables are immutable, which makes the code you present invalid. So, in my scenario, my decision makes sense.
In a more generic sense, you have to trade off the annoyance of not being able to write the code you present and the annoyance of not catching bugs because you return false instead of throwing. Reasonable people can come up in different places in that debate.

John Mertus

2008-05-03T21:56:50Z

Why not just return a dictionary from the function.  The key of the dictionary are the names of the elements of the class, the value objects.  For example
 var Person = GetPerson(<some id>);
 int age = Person["age"]).ToInt32()
 string name = Person["FirstName"].ToString();
(Here .ToInt32 is the damn extension C# should have for objects, why the hell doesn't it)
Of course  
 The big problem is the data binding becomes a var in the java sense; that it is like a late binding and fails at runtime not compile time.   But it gives a better syntax and is more readable than tuples.

David Nelson

2008-05-04T18:47:21Z

@John
"Here .ToInt32 is the damn extension C# should have for objects, why the hell doesn't it"
Because the vast majority of types cannot be reasonably represented by an Int32. Presumably if such a ToInt32 method existed, these types would all have to throw an exception. Why would you want to add a parsing method to every single object which will fail most of the time?

adamjcooper.com/blog

2008-06-03T16:59:59Z

The Quest for Quick-and-Easy Immutable Value Objects in C#

Luca Bolognese's WebLog

2008-07-15T05:46:24Z

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.