Using Nominal Types for Tuples

[Blog Map]  [Table of Contents]  [Next Topic]

When I first started writing code in the functional style, I used anonymous types quite often.  However, I have since modified my coding style to use nominal types more often, typically defined using automatic properties.  This leads to code that is easier to refactor.

This blog is inactive.
New blog: EricWhite.com/blog

Blog TOCThe following example (from the previous topic on anonymous types) shows projection of a collection of anonymous types:

public class Customer
{
public string Name { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
}

class Program
{
static void Main(string[] args)
{
Customer[] custList = {
new Customer {
Name = "Bob",
Address = "123 Main Street, Seattle, WA 98111",
Phone = "555-1234"
},
new Customer {
Name = "Bill",
Address = "555 Center Street, Tacoma, WA 97158",
Phone = "555-9999"
}
};

var newCustList =
custList.Select(
c => new
{
UCName = c.Name.ToUpper(),
UCAddress = c.Address.ToUpper()
}
);

foreach (var c in newCustList)
Console.WriteLine(c.UCName);
}
}

However, one problem with this code is that as written, we can't move the query into its own method.

A different approach, which I like more, is to define a nominal type for the tuple, and use automatic properties to define the members.  I really like automatic properties because you can define a class with n properties in n+2 lines of code.  The syntactic noise is kept to a minimum.  Depending on the circumstances, you can declare the tuple class as a nested class.

One of the characteristics of dynamic languages is the ability to add new properties to a tuple type very easily.  This characteristic is shared by C# when projecting using anonymous types.  However, I find that I have the same type of experience when using nominal types in the fashion described in this topic.  I don't find it particularly onerous to add new members to the tuple type using automatic properties.  I have a little macro that creates one for me, and all I need to type are the type and the name.  The malleability of tuple types is nearly as good as when using a dynamic type, except that you get strong typing, and a good Intellisense experience in VS.

Consider the following code, where the tuple is defined using a private named class, and the query and projection are refactored into a separate method.  The following code is attached to this page:

public class Customer
{
public string Name { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
}

class Program
{
private class UCCustomer
{
public string UCName { get; set; }
public string UCAddress { get; set; }
}

static IEnumerable<UCCustomer> ProjectUC(IEnumerable<Customer> source)
{
return source.Select(
c => new UCCustomer
{
UCName = c.Name.ToUpper(),
UCAddress = c.Address.ToUpper()
}
);
}

static void Main(string[] args)
{
Customer[] custList = {
new Customer {
Name = "Bob",
Address = "123 Main Street, Seattle, WA 98111",
Phone = "555-1234"
},
new Customer {
Name = "Bill",
Address = "555 Center Street, Tacoma, WA 97158",
Phone = "555-9999"
}
};

var newCustList = ProjectUC(custList);

foreach (var c in newCustList)
Console.WriteLine(c.UCName);
}
}

Notice in the above code that the object initializer for the tuple type is nearly identical to the object initializer when projecting an anonymous type.  The only difference is the naming of the type in the initializer.

When writing queries on the fly, anonymous types are handy.

Sometimes I'll expose the nominal tuple type as a public class, and it becomes part of the programming interface to the classes and methods that contain my FP code.  For an example of this approach, see Open XML SDK and LINQ to XML.

[Blog Map]  [Table of Contents]  [Next Topic]

UsingNominalTypesForTupples.cs