A C# library to write functional code - Part III - Records
Luca -
☕ 2 min. read
Other posts in the series:
-
-
- Part III - Records
- Part IV - Type Unions{.}
- Part V - The Match operator{.} 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 immutable value object. I talked at length about these fellows in this series of blog posts. In functional parlance, a Record is a Tuple that lets you access 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; } }
} public class Customer: Record<string, IEnumerable<Order>> { public Customer(string name, IEnumerable<Order> orders) : base(name, orders) { } public string Name { get { return state.Item1; } } public IEnumerable<Order> Orders { get { return state.Item2; } } }
You need to do three things: 1. Inherit from a generic Record class specifying the types of the properties as parameters 2. Add a constructor that calls back to the 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><T1, T2> {
-
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><T1, T2> 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 ‘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><T1, T2> STuple<T1, T2>(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><T1, T2>(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><T1, T2>;
<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.
0 Webmentions
These are webmentions via the IndieWeb and webmention.io.
13 Comments
Comments
Microsoft news and tips &r
2008-04-21T14:21:13ZPingBack from http://microsoftnews.askpcdoc.com/?p=3525
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
gOODiDEA
2008-04-21T21:04:54Z.NETRestLess-ASimpleRESTFrameworkASP.NETAJAXOverviewAndTechnicalTipsAC#libraryto...
Charlie Calvert's Community Bl
2008-04-23T16:58:14ZWelcome to the forty-third issue of Community Convergence. The last few weeks have been consumed by the
Eamon Nerbonne
2008-04-24T05:11:28ZBy 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.
lucabol
2008-04-24T13:13:10ZEamon: you are right. It is bad. As I said before, I was lazy.
ktmt
2008-04-25T11:13:00ZWow, 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.
amiya
2008-05-08T13:55:11Zhttp://www.amazingorissa.comhttp://www.amazingorissa.comhttp://www.amazingorissa.comhttp://www.amazingorissa.comhttp://www.amazingorissa.comhttp://www.amazingorissa.comhttp://www.amazingorissa.comhttp://www.amazingorissa.comhttp://www.amazingorissa.comhttp://www.amazingorissa.comhttp://www.amazingorissa.comhttp://www.amazingorissa.comhttp://www.amazingorissa.com
TimNew
2008-05-20T12:06:19ZThis'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!
pligg.com
2008-05-23T18:55:17ZPrevious 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:39ZThe Quest for Quick-and-Easy Class-Based Immutable Value Objects in C# - Part 1: Introduction
adamjcooper.com/blog
2008-06-03T17:00:02ZThe Quest for Quick-and-Easy Immutable Value Objects in C#
Luca Bolognese's WebLog
2008-07-15T05:46:24ZOther posts in the series: Part I - Background Part II - Tuples Part III - Records Part IV - Type Unions