A C# library to write functional code - Part III - Records - Luca Bolognese

A C# library to write functional code - Part III - Records

Luca -

☕ 2 min. read

Other posts in the se­ries:

  • Part I - Background

    • Part II - Tuples

      Well, in C# par­lance a Record is a sort of im­mutable value ob­ject. I talked at length about these fel­lows in this se­ries of blog posts. In func­tional par­lance, a Record is a Tuple that lets you ac­cess its items by name.

      You code Records like this:

      public class Order: Record<string, int> {
      public Order(string item, int qty): base(item,qty) {}
      public string Item { get { return state.Item1;}}
      public int Quantity { get { return state.Item2; } }
      

    } pub­lic class Customer: Record<string, IEnumerable<Order>> { pub­lic Customer(string name, IEnumerable<Order> or­ders) : base(name, or­ders) { } pub­lic string Name { get { re­turn state.Item1; } } pub­lic IEnumerable<Order> Orders { get { re­turn state.Item2; } } }

    You need to do three things:
    
      1. Inherit from a generic Record class specifying the types&nbsp;of the properties as parameters
      2. Add a constructor that calls back to the&nbsp;Record constructor
      3. Add getters to retrieve the values of the properties (no setters as it is immutable)
    
    This may seem like plenty of work, but in return you get structural equality. Coding that by hand every time you use a record would be a royal pain. You lose control of the base class, but that is often not a problem as in functional-land you more often use type unions than inheritance.
    
    How is it implemented?
    
    First of all it is an abstract class with as many generic parameters as properties that you need in your Record. Let's use two as an example.
    
    <pre class="code"><span style="color:rgb(0,0,255);">public</span> <span style="color:rgb(0,0,255);">abstract</span> <span style="color:rgb(0,0,255);">class</span> <span style="color:rgb(43,145,175);">Record</span>&lt;T1, T2&gt; {
    
    This abstract class has a field of type STuple:
    
    <pre class="code"><span style="color:rgb(0,0,255);">protected</span> <span style="color:rgb(0,0,255);">readonly</span> <span style="color:rgb(43,145,175);">STuple</span>&lt;T1, T2&gt; state;
    What is a STuple? Well it is exactly the same as the Tuple described in Part II, but coded as a struct instead of a class. The reason to use a struct is to not allocate an additional object on the stack. This allows this solution to be as &#8216;performant' as simply having coded the fields on the class itself. Or at least I think so
    
    The Record class also has a constructor that simply initialize the STuple:
    
    <pre class="code"><span style="color:rgb(0,0,255);">public</span> Record(T1 t1, T2 t2) { state = <span style="color:rgb(43,145,175);">F</span>.STuple(t1, t2); }</pre>
    
    <pre class="code"><font face="Verdana">where</font></pre>
    
    <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(43,145,175);">STuple</span>&lt;T1, T2&gt; STuple&lt;T1, T2&gt;(T1 t1, T2 t2) {
        <span style="color:rgb(0,0,255);">return</span> <span style="color:rgb(0,0,255);">new</span> <span style="color:rgb(43,145,175);">STuple</span>&lt;T1, T2&gt;(t1, t2);
    }</pre>
    
    The Equals method is very much the same as the Tuple's one, just delegating to the same DSEqual function that checks equality for Tuples.
    
    <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);">Record</span>&lt;T1, T2&gt;;
        <span style="color:rgb(0,0,255);">return</span> <span style="color:rgb(43,145,175);">F</span>.DSEquals(<span style="color:rgb(0,0,255);">this</span>.state, rightT.state);
    }</pre>
    
    That's it. Not too difficult as most of the implementation is based on the Tuple's code. Next post will hopefully be more interesting. It is about Type Unions.
13 Comments

Comments

Microsoft news and tips &#38;r

2008-04-21T14:21:13Z

gOODiDEA.NET

2008-04-21T21:04:17Z

.NET RestLess - A Simple REST Framework ASP.NET AJAX Overview And Technical Tips A C# library to write

.NETRestLess-ASimpleRESTFrameworkASP.NETAJAXOverviewAndTechnicalTipsAC#libraryto...

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

Eamon Nerbonne

2008-04-24T05:11:28Z

By the way, there's another reason your hash-code algorithm is unwise: Assuming the component hash-codes are uniformly distributed over the integers from 0 to 2^32-1 (thus interpreting the signed integers as unsigned integers here, for simplicity), your will not be:  a binary or never lowers the number of "on" bits; each bit of your result hash code has only a 25% chance to be off - which lowers the entropy of the overall hash code to be around 26 bits, as opposed to 32 bits.
Finally, tuples of tuples will hash particularly badly; and so will tuples with higher than 2-arity.

Eamon: you are right. It is bad. As I said before, I was lazy.

Wow, a little more and we'll finally have the easy-to-use record construct of Pascal in the 1980s.  Just declare a Record type and you're set.  I have (seriously) often wished for this in C# instead of cumbersome, separate struct or class def's.

This's a really excellent introduction. I think I begin to know what the functional code is after reading your posts and code. But I have some questions about this:
For the GetHashCode(), why don't you try "xor" other than "or"? I think "xor" will get a better job than the "or"~
For something about all the code, and I found TypeUnion<T> is really useless! Since I'll never have the change to use a member union!

Previous posts: Part I - Background Part II - Tuples Now that we know what Tuples are, we can start talking about Record, as they use a derivative of Tuples under the cover. But first, what is a record? Well, in C# parlance a Record is a sort of immutabl

adamjcooper.com/blog

2008-06-03T15:38:39Z

The Quest for Quick-and-Easy Class-Based Immutable Value Objects in C# - Part 1: Introduction

adamjcooper.com/blog

2008-06-03T17:00:02Z

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.