I've seen people use the Tuple class in C# code and I've even done it myself once. And I didn't like it. I'm still struggling to see find a case where using a Tuple would actually be a good idea versus the alternatives.
It seams like the most common argument for using Tuples in C# code is to save you from creating a new class or struct when you just want to pass some data in a structured type safe manner rather than using an array of objects. And the "only" disadvantage is that you can't name your properties.
Well creating the class is a one time thing and prevents you from accidently use the wrong tuple if you have two different concepts represented by the same tuple setup. And with a class you have nicely named properties instead of Item1, Item2 etc. So far a specific class sounds like a much better idea since you probably read the code much more than write it...
I've heard arguments that is the tuple only have custom types it is ok since then you know from the type what each item represents. While this is an improvement over using built in types where you have no clue to what it is I still don't see why it would be better than using a real type...
What if the data is very local. Let's say you want to pass a few values from one private function to another private function. A tuple wouldn't hurt here would it? Well it does in my opinion. This is the one case where I actually used tuples and I hated it. Because even though it is only the interface between two private methods, every time I need to look at one of them I struggle to remember "what was Item2 now again". And that sucks! And this is the case even when the tuple does not contain any built in types.
In my quest for a reason to use the Tuple I came up with a crazy scenario. What if I have two assemblies that need to share some data but I don't want to share any data types. Could I use a tuple then? Well first of all if I'm not sharing any types the tuple will only be using built in types which is inherently a bad idea (see above). Then if these two assemblies are interacting without sharing any data types (which I hope you agree is a weird scenario) the use of a Dictionary where you can name your data rather than just using a Tuple seems like a better idea to me for readability of your code. For performance and compiler support that you actually provide all data it might be a bad idea. But more important; if you are in this situation I think there is something wrong with the design of your application...
So help me out there; can you find any good reason to actually use the Tuple?
Agreed, I've used them in the past and gone back and replaced them as they don't describe at all what they are doing. The word Tuple is so ambiguous as for new devs to get a dictionary (or Google it) which illustrates the point.
ReplyDeleteYes, I use them when I am exposing an private service call, for example I am writing a service so I can use Javascript to retrieve data to update the UI but the data is coming from multiple entities and I only need to show a couple pieces. It makes more sense in this one off case to use a Tuple rather than create a class to be used only one time.
ReplyDeleteI think the argument that is is a "one off" is a little sketchy... A lot of the code I wrote is "only used one time"... I don't create abstractions for reuse I create them to make the code easy to understand by somebody else who gets woken up in the middle of the night 2 years from now... Sure it is convenient to use a tuple if it is only in one single place, but don't you agree a class would be better? Like if somebody else wrote the class for you, would you not use it because the tuple is actually better?
DeleteThe only place that I've found myself using tuples is when I was working with the BackgroundWorker class and needed to pass multiple parameters. I quickly found out that from a maintenance prospective this wasn't ideal as I would have to find the calling methods to determine what I was passing to it.
ReplyDelete@Eric, why not create an anonymous type to serialize and pass back instead of using a tuple? I've never found a good reason to use a tuple. Seems like something that was created to show off generics and accidentally got left in the framework.
ReplyDeleteI've found them useful particularly when returning multiple values - and when I have a (private) collection that I want to store multiple values inside of. Furthermore, when working against a delegate that only provides a single parameter, tuples are very useful for stuffing multiple values into that argument. Generally speaking, I only create 2- and 3-tuples: if it grows larger than that, then I'd introduce a class.
ReplyDeleteIn other languages, such as F#, tuples are absolutely necessary and very powerful. However, the F# implementation is different since tuples are actually built into the language itself.
@Nelson; Considering your first paragraph I don't see why Tuples are good since a specific class or struct would achieve the same thing except you get better names at the cost of having to create the class. Wouldn't you agree that a specific class i better in these cases? Is a tuple really better in those cases or just a result of laziness?
DeleteRegarding tuples and various functional languages; I specifically titled this post "When to use tuples in C#" since I know they are more important in several functional languages. However I would still argue they are a terrible construct even there. And I don't think I'm alone... For example Erlang had records to hide some of the ugliness of tuples but in the most recent release they added maps as a new type since it gives the benefits of a tuple with pattern matching but at the same time lets you access the parts of the tuple with sensible names rather than by position. So I'm actually not sure tuples are actually needed in functional languages like F# either... I guess that would be an interesting post too...
I was initially not hot on tuples in F#, because coming from C# I got used to tuples being just poorly, lazily designed classes. At that point, I LOVE tuples in F#. The obvious issue with tuples in C# is the lack of pattern matching, which makes them totally useless. I think tuples can actually be good design. Consider this snippet for instance:
Deletelet xs = [ 1 .. 10 ]
let evens,odds = xs |> List.partition (fun x -> x % 2 = 0)
In this case, I don't think adding a class or record to hold the result helps in any way. The container would just introduce friction in retrieving the values, and have no particular meaning in the domain. Similarly, consider Seq.zip and Seq.unzip: these are all about creating/exploding generic pairs, and don't particularly care what the pair contains. F# also has Records, and I use them all the time, when I am dealing with an entity that has a meaning/name in the domain. I use tuples everywhere as well, but for slightly different purposes.
A big short-coming of tuples in C# is that they don't have value semantics.
ReplyDeleteSay we have ...
var t1 = new Tuple(99, 235);
var t2 = new Tuple(99, 235);
bool cmp1 = t1 == t2; // evaluates to FALSE !!!
bool cmp2 = t1 < t2; // does NOT compile !!!
The above example shows that the usefulness of tuples is rather limited in C#. In F# the above would both compile and evaluate to expected results.
If I remember correctly, the primary motivation to incorporate tuples in C# was to provide a clean and efficient way of calling F# functions from C#. As to their usefulness in functional languages, I can assure you that they are extremely useful and are used extensively.
I use Tuple when (and only when) I am in a function and are executing an anonymous method that takes only an object state as parameter (a new thread for example), and only if this anonymous method is defined within the same method. The reasons are that it is an call internal to a function that cannot be executed from outside the function, and I cannot create a struct och class that is only reacable from a specific function and functions defined within that function. That is; I don't let a Tuple be apart of a contract in any other way.
ReplyDeletevoid Main()
{
var theDelay = 5000;
Task.Factory.StartNew(obj =>
{
var tuple = obj as Tuple;
var delay = tuple.Item1;
Task continueTask = tuple.Item2;
// Rediculus example
Task.Delay(tuple.Item1);
continueTask.RunSynchronously();
}, Tuple.Create(theDelay, () => DoThisThing()));
}
void DoThisThing()
{
// ...
}
Tuples make having a compound key on a Dictionary painless, but they don't do much for code readability.
ReplyDeleteI think you might have the one example where a Tuple would actually make sense in C#. Assuming you create the tuple in a single private function and only use it to access a private dictionary.
DeleteWhy don't you all read an answer on Stackoverflow from the guy who co-authored the C# compiler? Tuples are very useful.
ReplyDeletehttp://stackoverflow.com/questions/3089706/what-requirement-was-the-tuple-designed-to-solve
Vince, the stack overflow answer is missing my point and also bringing up my point in several (unanswered) comments. Yes tuples are useful. But apart from the private composite key I do not see tuples as the best alternative since tuples lack clarity with its generic names. For functional languages where pattern matching on tuples is used extensivly they are needed, but yet I see people add functions to access data in the tuple where possible for clarity.
Delete