Trouble with tuples
07 Jan

Trouble with tuples

  I like C# for a lot of reasons. It has a responsive IDE, readable syntax, and a great feature set. It is not perfect though. Although its feature set is vast some of those features do not seem to be as well implemented as they could be. One of those features is the addition of tuples.

  I think tuples are extemely useful. Anytime i feel the need for a function to return 2 values I prefer to use a tuple over creating all the boilerplate code of a class. Those values can then be stored and passed together (even between classes), or split up immediately into 2 separate variables depending on the scenario at hand. My problem is that accessing data in c# tuples is not as transparent as it could be, when using the tuples "Item1" and "Item2" properties.

C#

private Tuple<int, int> GetAssociationAndMember()
{
    //...
    return Tuple<int,int>(association,member);
}
// what do we call this?
var AssociationIdThenMemberId = GetAssociationAndMember();

// yuck
var associationId = AssociationIdThenMemberId.Item1;
var memberid = AssociationIdThenMemberId.Item2;

  I complain about this issue frequently. It doesn't seem to be a problem in other languages as they allow you to break apart the tuple using syntax that never generalizes the values. Take python for instance:

Python

def __GetAssociationAndMember(self):
    ''' ... '''
    return (association, member)

''' less code, easy to understand, difficult to obfuscate '''
associationId, memberId = self.__GetAssociationAndMember()

You might say: "but that is because C# is type safe." To which I would say: "so is scala"

Scala

def GetAssociationAndMember = {
    /// ...
    Tuple2(association,member);
}

var associationId,memberId = GetAssociationAndMember;

  I hope this accurately illustrates my issue. But how do we fix it? Fortunately I found a serviceable solution in the linq library's "select" method. Which for some reason is not included as a tuple extension out of the box. The extension is straight-forward enough though, so we can craft it on our own.

C#

public static TResult Select<T1, T2, TResult>(this Tuple<T1, T2> source, Func<T1, T2, TResult> selector)
{
    return selector(source.Item1, source.Item2);
}
// this allows us ...
GetAssociationAndMember().Select((associationId,memberId) => {
    // do things with the aptly named variables
});

  There we go. Now the ugliness that is "Item1,Item2" is hidden away. Whenever we have a method that needs to return 2 values we can now be lazy and use a tuple, instead of creating a specialized class, or even worse using an out variable. (shudder.)