Why use tuples instead of objects?

Solution 1:

First of all, a tuple is quick and easy: instead of writing a class for every time you want to put 2 things together, there's a template that does it for you.

Second of all, they're generic. For example, in C++ the std::map uses an std::pair of key and value. Thus ANY pair can be used, instead of having to make some kind of wrapper class with accessor methods for every permutation of two types.

Finally, they're useful for returning multiple values. There's really no reason to make a class specifically for a function's multiple return values, and they shouldn't be treated as one object if they're unrelated.

To be fair, the code you pasted is a bad use of a pair.

Solution 2:

Tuples are used all the time in Python where they are integrated into the language and very useful (they allow multiple return values for starters).

Sometimes, you really just need to pair things and creating a real, honest to god, class is overkill. One the other hand, using tuples when you should really be using a class is just as bad an idea as the reverse.

Solution 3:

The code example has a few different smells:

  • Reinventing the wheel

There is already a tuple available in the framework; the KeyValuePair structure. This is used by the Dictionary class to store pairs, but you can use it anywhere it fits. (Not saying that it fits in this case...)

  • Making a square wheel

If you have a list of pairs it's better to use the KeyValuePair structure than a class with the same purpose, as it results in less memory allocations.

  • Hiding the intention

A class with properties clearly shows what the values mean, while a Pair<int,int> class doesn't tell you anything about what the values represent (only that they are probably related somehow). To make the code reasonably self explanatory with a list like that you would have to give the list a very desciptive name, like productIdAndQuantityPairs...

Solution 4:

For what its worth, the code in the OP is a mess not because it uses tuples, but because the values in the tuple are too weakly typed. Compare the following:

List<Pair<Integer, Integer>> products_weak = blah1();
List<Pair<Product, Integer>> products_strong = blah2();

I'd get upset too if my dev team were passing around IDs rather than class instances around, because an integer can represent anything.


With that being said, tuples are extremely useful when you use them right:

  • Tuples exist to group ad hoc values together. They are certainly better than creating excessive numbers of wrapper classes.
  • Useful alternative to out/ref parameters when you need to return more than one value from a function.

However, tuples in C# make my eyes water. Many languages like OCaml, Python, Haskell, F#, and so on have a special, concise syntax for defining tuples. For example, in F#, the Map module defines a constructor as follows:

val of_list : ('key * 'a) list -> Map<'key,'a>

I can create an instance of a map using:

(* val values : (int * string) list *)
let values = 
    [1, "US";
     2, "Canada";
     3, "UK";
     4, "Australia";
     5, "Slovenia"]

(* val dict : Map<int, string> *)
let dict = Map.of_list values

The equilvalent code in C# is ridicuous:

var values = new Tuple<int, string>[] {
     new Tuple<int, string>(1, "US"),
     new Tuple<int, string>(2, "Canada"),
     new Tuple<int, string>(3, "UK"),
     new Tuple<int, string>(4, "Australia"),
     new Tuple<int, string>(5, "Slovenia")
     }

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

I don't believe there is anything wrong with tuples in principle, but C#'s syntax is too cumbersome to get the most use out of them.