proposals/csharp-7.1/infer-tuple-names.md
In a number of common cases, this feature allows the tuple element names to be omitted and instead be inferred. For instance, instead of typing (f1: x.f1, f2: x?.f2), the element names "f1" and "f2" can be inferred from (x.f1, x?.f2).
This parallels the behavior of anonymous types, which allow inferring member names during creation. For instance, new { x.f1, y?.f2 } declares members "f1" and "f2".
This is particularly handy when using tuples in LINQ:
// "c" and "result" have element names "f1" and "f2"
var result = list.Select(c => (c.f1, c.f2)).Where(t => t.f2 == 1);
There are two parts to the change:
y (identifier), x.y (simple member access) and x?.y (conditional access).x.y().ItemN, Rest, and ToString.Note that the rule for handling duplicates is different than that for anonymous types. For instance, new { x.f1, x.f1 } produces an error, but (x.f1, x.f1) would still be allowed (just without any inferred names). This avoids breaking existing tuple code.
For consistency, the same would apply to tuples produced by deconstruction-assignments (in C#):
// tuple has element names "f1" and "f2"
var tuple = ((x.f1, x?.f2) = (1, 2));
The same would also apply to VB tuples, using the VB-specific rules for inferring name from expression and case-insensitive name comparisons.
When using the C# 7.1 compiler (or later) with language version "7.0", the element names will be inferred (despite the feature not being available), but there will be a use-site error for trying to access them. This will limit additions of new code that would later face the compatibility issue (described below).
The main drawback is that this introduces a compatibility break from C# 7.0:
Action y = () => M();
var t = (x: x, y);
t.y(); // this might have previously picked up an extension method called “y”, but would now call the lambda.
The compatibility council found this break acceptable, given that it is limited and the time window since tuples shipped (in C# 7.0) is short.