A couple of nice Tuple use cases
Posted on Monday, 16th March 2020
C# has had a Tuple type (
System.Tuple) for sometime now, however a re-occuring theme was it generally lacked the utility that tuples in languages with native support had. This partly due to the fact that it was really just a class utilising generics with no real language or runtime support, resulting in its adoption being rather limited.
Since C# 7 and the introduction of the
ValueTuple type (freeing up some GC cycles) and tuple deconstruction, things seem to have changed and I’ve noticed more and more libraries and developers utilising them, myself included.
With that in mind I’d like to highlight a couple of creative use cases I’ve seen people using that I’d never considered before:
I first learned about this pattern at a recent Jon Skeet talk I attended at the .NET South West meet up I co-organise. Jon was demoing some new C# 8 language features and stopped to talk about how he’d adopted this particular pattern.
Given the following constructor we can make this a little shorter without losing much readability using tuples:
When we look at the lowered version of the code using a tool such as SharpLab, we can see that the Tupled version is lowered to exactly the same syntax as the version before which means there’s no cost in using such a pattern.
As you might expect, you can also use the same approach for methods. Again this incurs no additional cost:
Tuple / Deconstructor loops
Another pattern I stumbled upon is using tuples within a loop. For instance given the following dictionary of people, due to
KeyValuePair now featuring a Deconstruct method, we can unpack the contents in a few ways.
Traditionally we’d have done this:
With the cost efficiently of the
ValueTuple type we can start to get creative:
At this point we can go one further by adding a Deconstruct method in our
Person class, allowing us to deconstruct the properties into a tuple:
Benchmarking the above patterns
For peace of mind, let’s benchmark the aforementioned patterns with BenchmarkDotNet to see what impact it has:
| Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated | |---------------------- |---------:|--------:|--------:|-------:|------:|------:|----------:| | List | 142.9 ns | 2.92 ns | 6.17 ns | 0.0439 | - | - | 184 B | | DeconstructionToTuple | 138.8 ns | 2.21 ns | 2.07 ns | 0.0439 | - | - | 184 B |
As you can see they’re pretty much equal in terms of cost, with the added benefit of a more expressive syntax.
Hopefully the patterns highlighted above are as new to you as they were to me, and sparked some more interest in the utility of the
ValueTuple type, especially when used in conjunction with
KeyValuePair and/or the
Deconstruct method. I can only assume we’ll start to see more patterns like this emerge in time as Record types make their way into C#.
Enjoy this post? Don't be a stranger!
Follow me on Twitter at @_josephwoodward and say Hi! I love to learn in the open, meet others in the community and talk Go, software engineering and distributed systems related topics.