views:

352

answers:

7

I have seen the Tuple introduced in .Net 4 but I am not able to imagine where can be it be used. We can always make a Custom class or Struct.

Edit: I am looking for an example which can also be considered inside the bracket of best practices.

+8  A: 

That's the point - it is more convenient not to make a custom class or struct all the time. It is an improvement like Action or Func ... you can make this types yourself, but its convenient that they exist in the framework.

tanascius
+6  A: 

Here's a small example - say you have a method that needs to lookup a user's handle and email address, given a user Id. You can always make a custom class that contains that data, or use a ref / out parameter for that data, or you can just return a Tuple and have a nice method signature without having to create a new POCO.

public static void Main(string[] args)
{
    int userId = 0;
    Tuple<string, string> userData = GetUserData(userId);
}

public static Tuple<string, string> GetUserData(int userId)
{
    return new Tuple<string, string>("Hello", "World");
}
Tejs
This is a good example however, does not justify the usage of Tuple.
Amitabh
A tuple is a decent fit here since you're returning distinct values; but a tuple shines more when you're returning multiple values of different *types*.
Mark Rushakoff
Another good example would be int.TryParse, as you could eliminate the output parameter and instead use a Tuple. So you could have `Tuple<bool, T> TryParse<T>(string input)` and instead of having to use an output parameter, you get both values back in a tuple.
Tejs
@Tejs - in fact, that's exactly what happens when you call any TryParse method from F#.
Joel Mueller
That's convenient then, as I was just starting to learn F#!
Tejs
+2  A: 

Tuples are heavily used in functional languages which can do more things with them, now F# is a 'official' .net language you may want to interoperate with it from C# and pass them between code written in two languages.

Mant101
+3  A: 

C#'s tuple syntax is ridiculously bulky, so tuples are painful to declare. And it doesn't have pattern matching, so they're also painful to use.

But occasionally, you just want an ad-hoc grouping of objects without creating a class for it. For example, let's say I wanted to aggregate a list, but I wanted two values instead of one:

// sum and sum of squares at the same time
var x =
    Enumerable.Range(1, 100)
    .Aggregate((acc, x) => Tuple.Create(acc.Item1 + x, acc.Item2 + x * x));

Instead of combining a collection of values into a single result, let's expand a single result into a collection of values. The easiest way to write this function is:

static IEnumerable<T> Unfold<T, State>(State seed, Func<State, Tuple<T, State>> f)
{
    Tuple<T, State> res;
    while ((res = f(seed)) != null)
    {
        yield return res.Item1;
        seed = res.Item2;
    }
}

f converts some state into a tuple. We return the first value from the tuple and set our new state to the second value. This allows us to retain state throughout the computation.

You use it as such:

// return 0, 2, 3, 6, 8
var evens =
    Unfold(0, state => state < 10 ? Tuple.Create(state, state + 2) : null)
    .ToList();

// returns 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
var fibs =
    Unfold(Tuple.Create(0, 1), state => Tuple.Create(state.Item1, Tuple.Create(state.Item2, state.Item1 + state.Item2)))
    .Take(10).ToList();

evens is fairly straightforward, but fibs is a little more clever. Its state is actually a tuple which holds fib(n-2) and fib(n-1) respectively.

Juliet
+3  A: 

There's an excellent article in MSDN magazine that talks about the belly-aching and design considerations that went into adding Tuple to the BCL. Choosing between a value type and a reference type is particularly interesting.

As the article makes clear, the driving force behind Tuple was so many groups inside of Microsoft having a use for it, the F# team up front. Although not mentioned, I reckon that the new "dynamic" keyword in C# (and VB.NET) had something to do with it as well, tuples are very common in dynamic languages.

It is otherwise not particularly superior to creating your own poco, at least you can give the members a better name.

Hans Passant
+2  A: 

I used a tuple to solve Problem 11 of Project Euler:

class Grid
{
    public static int[,] Cells = { { 08, 02, 22, // whole grid omitted

    public static IEnumerable<Tuple<int, int, int, int>> ToList()
    {
        // code converts grid to enumeration every possible set of 4 per rules
        // code omitted
    }
}

Now I can solve the whole problem with:

class Program
{
    static void Main(string[] args)
    {
        int product = Grid.ToList().Max(t => t.Item1 * t.Item2 * t.Item3 * t.Item4);
        Console.WriteLine("Maximum product is {0}", product);
    }
}

I could have used a custom type for this, but it would have looked exactly like Tuple.

Craig Stuntz
+2  A: 

A few examples off the top of my head:

  • An X and Y location (and Z if you like)
  • a Width and Height
  • Anything measured over time

For example you wouldn't want to include System.Drawing in a web application just to use Point/PointF and Size/SizeF.

James Westgate