BT

C# Futures: Tuples and Anonymous Structs

| by Jonathan Allen on Apr 27, 2015. Estimated reading time: 3 minutes |

With C#6 nearing completion, plans are already being laid for C# 7. While nothing is definite yet, they are starting to categorize proposals in terms of “interest and estimated plausibility”. In this series, we’ll be looking at some of the proposals starting with language support for tuples.

The purpose of a tuple is to create a lightweight way to return multiple values from a function. Good tuple support eliminates the need for out parameters, which are usually considered to be cumbersome. Moreover, out parameters are incompatible with async/await, making them useless in many scenarios.

What about the Tuple class?

The .NET Framework has a Tuple class since version 4. However, most developers consider it to only be useful under very limited circumstances. First of all, Tuple is a class. This means that memory has to be allocated when using it, which in turn increases memory pressure and makes GC cycles more frequent. For it to compete with out parameters in terms of performance it needs to be a structure.

The second issue involves API design. If you see a return type of Tuple<int, int> that doesn’t really tell you anything. Every use of the function would require checking the documentation twice, once when writing it and again during the code review. It would be far more useful if the return type were something like Tuple<int count, int sum>.

Anonymous Structs

Consider these lines:

public (int sum, int count) Tally(IEnumerable<int> values) { ... }
var t = new (int sum, int count) { sum = 0, count = 0 };

Under the proposal, either line would define a new anonymous value type with sum and count properties. Note that unlike an anonymous class, the anonymous struct requires you to explicitly list the property names and types.

A benefit of using structs is that they define Equals and GetHashCode automatically. Though one could argue that the default implementation isn’t very efficient and the compiler should provide one instead.

Unpacking Tuples

An important part of the tuple proposal is the ability to unpack tuples with a single line of code. Consider this block of code:

var t = Tally(myValues);
var sum = t.Sum;
var count = t.Count;

With unpacking, it becomes simply:

(var sum, var count) = Tally(myValues);

Not yet decided is whether or not you can unpack a tuple without declaring new variables. Or in other words, can you omit ‘var’ and use a pre-existing local variable instead.

Returning Tuples

There are two proposals being considered for how tuples would be returned from a function. The first is fairly easy to understand:

return (a, b);

The second option has no return statement at all. Consider this example,

public (int sum, int count) Tally(IEnumerable<int> values)
{
    sum = 0; count = 0;
    foreach (var value in values) { sum += value; count++; }
}

Implicitly created local/return variables isn’t a new concept. Visual Basic was originally designed that way, though it became unpopular once VB 7 introduced the return statement. It also mirrors what you would write if you were using out parameters. Still, not seeing a return statement would be somewhat disconcerting to many developers.

Other Issues

Tuple support is a rather complex topic. While this article covers the day-to-day aspects, many details will have to be resolved from the compiler writer /advanced user perspective.

Should tuples be mutable? This could be useful from a performance or convenience standpoint, but may make the code more error prone, especially when dealing with multi-threading.

Should tuples be unified across assemblies? Anonymous types are not unified, but unlike anonymous types these will be exposed as part of an API.

Can tuples be converted into other tuples? Superficially, if they have the same type structure but different property names. Or the same property names, but wider property types.

If you pass a tuple of two values to a function that takes two parameters, will be tuple be automatically unpacked (splatted)? Conversely, can you “unsplat” a pair of arguments into one tuple parameter?

Rate this Article

Relevance
Style

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Tell us what you think

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

One of the best lesser known but very useful constructs by Binoj Antony

Although Tuple with two values is pointless due to existence of KeyValuePair<T, K>, for more than two values its awesome, taking it beyond to be passed as parameters to methods that unpacks into two and unsplat etc may be going overboard, and maybe a little more difficult to find acceptance considering the low usage of tuples, but having proper property names to access the values instead of the Item1, Item2 etc will definitely make it more attractive to use..

Re: One of the best lesser known but very useful constructs by Joseph Musser

I've preferred Tuple`2 over KeyValuePair`2 just because the key-value relationship semantics the latter implies would be misleading.

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

2 Discuss
BT