C# - When to use value tuples and when to use classes

Value tuples were introduced with C# 7. The original tuples have been around since 2010 when they were released with .Net Framework 4.0. Even though tuples have been around for 10 years they were never as widely used as the new value tuples released with C# 7 are. One of the reasons is that they made code hard to read as their members could only be accessed as Item1, Item2, Item3 etc. There was no way to change the names of the members, but this was changed with the introduction of value tuples along with some sugar syntax.

The old types of tuples vs classes

Why do I mention the old type of tuples in this post? Because I believe the biggest problem with them was their readability. Classes give the readability that the original tuples did not - their members could be named whatever you wanted. Let us look at an example.

var person = new Tuple<string, string>("Peter","Rasmussen");
var name = person.Item1;
var lastname = person.Item2;

In the above you can see the problem, the only way to access the values are as Item1 and Item2. Now think of a solution where this tuple is passed around in the code between several methods. At some point you will lose track of which value is which. Especially if there are more than just two, adding a new value gives you yet another itemX you need to remember. Alternatively you can use a class:

public class Person
{
    public string Name { get; set; }
    public string Lastname { get; set; }
}

var person = new Person
{
    Name = "Peter",
    Lastname = "Rasmussen"
};
var name = person.Name;
var lastname = person.Lastname;

In the above I have introduced a simple Person class containing the members Name and Lastname. It is obviously easier to figure out what is going on when you have good naming in your code base for your variables / properties / members.

The downside of the above is that you have an "extra" class in your code base. Depending on the context this might feel like it is bloating your code base. If you only wish to return two values for a method and the class would only be used for that method, having a class might seem like too much. This is where the new value tuples and their syntactic sugar comes in.

Value tuples vs classes

Using the new value tuples our previous example would look like the following:

var person = (Name: "Peter", Lastname: "Rasmussen");

var name = person.Name;
var lastname = person.Lastname;

The above does not lose readability when compared with the class example. The members have good names and can be accessed using these. It is less verbose, yet you may argue that you lose readability as the members are not defined as explicit strings. However I see this as similar to the impicit vs explicit type declaration discussion (using the var keyword vs not using the var keyword). Where there are cons and pros either way, but most codebases that I interact with use var.

If we just compare the two examples, there is only the downside, which is that the class takes up more space in your code base, so it is a win for the new value tuples. However were we to reuse the class or to use this "structure" all over our code base then the class would be less verbose. Every time the value tuple is passed to a method, that method has to define it, instead of just using the class. You can see it in the examples below:

public class Person
{
    public string Name { get; set; }
    public string Lastname { get; set; }
}

public Person GetPerson (Person person)
{
    return person;
}

The above example is a little bit silly, but it is great for showing this point. It is a method that takes a person and returns it, we have reused the Person class from before.

Below we make the same signature of a method using a value tuple instead:

public (string Name, string Lastname) GetPerson((string Name, string Lastname) person)
{
    return person;
}

As you can see it is much more verbose as the values of the tuple are not "contained" but rather spilled out in the input and output. Every method where your tuple is passed along has to define the tuple members. There is currently no way to make a signature of a tuple and reuse that. Again, this is not a problem if you only wish to return two strings and not intend to reuse the tuple. The above only contains two strings, it could contain a lot more values than that, the more values the more it would make sense to use a class.

So when should you use a class rather than a value tuple? It depends! As mentioned the syntactic sugar of the value tuple is great for returning a couple of variables rather than having to introduce a class. However value tuples can bloat the code base if every method signature contains tuples with several members.

Remember you can always start with a value tuple and make it a class later on if it becomes hard to handle. So far in this post I have focused on the readability of code when comparing value tuples and classes, as I believe this is the biggest difference. However there are some other differences that you may want to take into account:

  • Classes are passed as references and tuples by value. Is this a problem? Probably not, but if you pass around large value tuples in your code base it may slow it down. You can use the ref keyword to remedy this.
  • Tuple names may not be available at runtime. You cannot always use reflection to get the names of your tuple members at runtime. Julien Couvreur puts it this way: "The runtime type is only ValueTuple (no names). The names only help at compile time, as syntactic sugar for ItemN". I believe there is an exception to this: when a method returns a valuetuple you can use the TransformNames property using reflection to attain the names.

That is it!

This was my post comparing classes and tuples for carrying values, I hope you found it useful, if you did or did not please let me know in the comments down below :)

If you wish to see the syntax and different ways you can use value tuples, please see my post on this.