Tuple equality – C# 7.3 in Rider and ReSharper

The Early Access Preview (EAP) versions of ReSharper 2018.2 and Rider 2018.2 added support for C# 7.3. In this series, we are looking at these new language features in C# 7.3. Today, we will cover tuple equality.

Tuple equality

More language evolution can be found in support for tuples. In C# 7.0, C# 7.1 and C# 7.2, the concept of value tuples and deconstructing tuples was introduced and expanded upon. In essence, some syntactic candy that provides a memory-friendly and developer-friendly way of working with tuples.

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

// C# 6

vartuple=newTuple<string,bool>("Jason",false);

if(tuple.Item2)

{

// ...

}

// C#7.0+

vartuple=(name:"Jason",isEmployee:false);

if(tuple.isEmployee)

{

// ...

}

C# 7.3 builds on top of this foundation and adds tuple equality (spec). The C# language now lets us compare equality of two tuples more easily. Instead of having to compare all of the tuple’s items one by one, we can check equality (using == or !=) on the tuple itself. Here’s a code snippet to help grok this:

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

vartuple1=(name:"Jason",isEmployee:false);

vartuple2=(name:"Jason",isEmployee:false);

// Before C# 7.3

if(tuple1.name==tuple2.name&&tuple1.isEmployee==tuple2.isEmployee)

{

// ...

}

// With C# 7.3

if(tuple1==tuple2)

{

// ...

}

This is pretty nifty compiler magic and syntactic sugar. Imagine comparing a tuple with 5 items, or a tuple with two items that are nullable…

It’s worth mentioning that tuple equality also works with tuple expressions, which can improve readability on some cases. The following statements are equivalent in C# 7.3:

C#

1

2

3

4

5

6

// C# 7.2 and earlier:

if(employee.firstName=="John"&&employee.surname=="Doe"){...}

// C# 7.3:

if(employee==("John","Doe")){...}

if(employee==(firstName:"John",surname:"Doe")){...}

What with nullable types? Before C# 7.3, we’d have to check all tuple items for null before comparing equality. With C# 7.3, we can instead check equality at the tuple level:

C#

1

2

3

4

5

6

7

vartuple1=((DateTime?)null,(DateTime?)null);

vartuple2=(DateTime.UtcNow,DateTime.UtcNow);

if(tuple1!=tuple2)

{

// ...

}

Under the hood, the C# compiler uses lowering to convert this language feature to what we’d normally have to write, as we can see in the generated Intermediate Language (IL) code (ReSharper | Tools | IL Code). The compiler converted our a == b check into many IL instructions that check whether our tuple’s nullable DateTime instances have a value.

Do check the specification for tuple equality, there are some interesting cases in there as well, for example when using nested tuples – think (string name, (string employee, DateTime employmentDate)).