Microsoft is hard at work on C# 7, the next version of C#. In this post, I'll look at tuples, one of the new features proposed for C# 7. So what are tuples, why do we need them, and how do they differ from what we have already.

Tuples are a way to temporarily group multiple values together. Currently, C# handles inputs and outputs asymmetrically. There is syntactic support for passing multiple inputs to a method, but you can only return a single output from a method. The addition of tuples makes inputs and outputs symmetric by allowing multiple outputs from a method.


Now you might be thinking, but I can do that already. I can create a struct, create a class, use .NET 4's Tuple class, or use out parameters. And you can and you should continue using those where they make sense. But each of those approaches causes friction when you merely want to return multiple values from a method.

Defining a new struct or class is a lot of effort for something that is single use. Using .NET 4's Tuple class avoids that, but now you're stuck with non-descriptive variable names (Item1, Item2, and so on). Additionally, being a class, you have the garbage collection overhead, albeit small, of allocating the Tuple.

Another way to return multiple values from a method is out parameters. But they cannot be used in async methods and are awkward to use: you need to declare the variables first and var cannot be used (although this may change as out parameters are also getting attention in C# 7).

Tuple Syntax

The new syntax for tuples mirrors the syntax for input parameters: a comma separated list of variable declarations inside parentheses. For example, here is the signature for a find method that searches the input for a match and returns a tuple containing both the index and item as output.

public (int index, T item) Find<T>(IEnumerable<T> input, Predicate<T> match) { ... }

The tuple element names are optional and can be left off:

public (int, T) Find<T>(IEnumerable<T> input, Predicate<T> match) { ... }

Constructing Tuples

A tuple can be constructed in three different ways. There is a verbose syntax:

var output = new (int index, T item) { index = i, item = currentItem };

A shorter syntax that uses type inference:

var output = (index: i, item: currentItem);

And a context sensitive syntax:

return (i, currentItem);

Accessing Tuple Elements

There are also three different ways to access a tuple's elements. They can be accessed by name:

var t = Find(values, v => v == "special");
var index = t.index;
var item = t.item;

By their default position based names:

var index = t.Item1;
var item = t.Item2;

And by deconstructing a tuple into its constituent parts:

(var index, var item) = Find(values, v => v == "special");

Alternatively, the var can go outside the parentheses:

var (index, item) = Find(values, v => v == "special");

Tuple Semantics

Tuples are value types and are implemented behind the scenes using structs with a public mutable field for each element. So the garbage collector is saved from cleaning up after them. Furthermore, as they're temporary and normally deconstructed once returned, the disadvantage of structs (the cost of copying on assignment) does not come into play.

As structs, tuples also get built-in value semantics. Namely, Equals and GetHashCode are implemented automatically. Two tuples are equal and have the same hash code when their elements are pair-wise equal.

The names are actually just syntactic sugar. Once compiled, they are referred to as Item1 and Item2 instead of index and item. Because of this, tuples can be assigned and converted to other tuples as long as the types appear in the same order. However, it is planned that the compiler will warn or throw an error for common mistakes like swapping names around.

Tuple Usage

Tuples are for temporarily grouping variables, so are useful for returning multiple parameters that will be used immediately by the caller. For longer lived groupings it is better to keep using existing mechanisms like classes.

Because tuples have value semantics, they're useful in situations besides returning multiple values. For example, they can be used to form a compound key for a dictionary:

var dictionary = new Dictionary<(int, int), string>();

Tuples can also be used in async methods:

public async Task<(int index, T item)> FindAsync<T>(IEnumerable<T> input, Predicate<T> match) { ... }

As C# 7 is still being developed, all these details are subject to change. But the current proposal for tuples is promising and tuples look set to be a great addition to C# that will address some common annoyances.