{"id":1036,"date":"2017-11-01T10:45:52","date_gmt":"2017-11-01T02:45:52","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/seteplia\/?p=1036"},"modified":"2019-06-11T22:14:31","modified_gmt":"2019-06-12T05:14:31","slug":"dissecting-the-tuples-in-c-7","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/premier-developer\/dissecting-the-tuples-in-c-7\/","title":{"rendered":"Dissecting the tuples in C# 7"},"content":{"rendered":"<p><a href=\"http:\/\/referencesource.microsoft.com\/#mscorlib\/system\/tuple.cs,9124c4bea9ab0199\"><code>System.Tuple<\/code><\/a> types were introduced in .NET 4.0 with two significant drawbacks: (1) tuple types are classes and (2) there was no language support for constructing\/deconstructing them. To solve these issues, C# 7 introduces new language feature as well as a new family of types (*).<\/p>\n<p>Today, if you need to glue together two values to return them from a function or put two values in a hash set you can use <code>System.ValueTuple<\/code> types and construct them using a handy syntax:<\/p>\n<pre class=\"lang:default decode:true \">\/\/ Constructing the tuple instance\r\nvar tpl = (1, 2);\r\n            \r\n\/\/ Using tuples with a dictionary\r\nvar d = new Dictionary&lt;(int x, int y), (byte a, short b)&gt;();\r\n\r\n\/\/ Tuples with different names are compatible\r\nd.Add(tpl, (a: 3, b: 4));\r\n\r\n\/\/ Tuples have value semantic\r\nif (d.TryGetValue((1, 2), out var r))\r\n{\r\n    \/\/ Deconstructing the tuple ignoring the first element\r\n    var (_, b) = r;\r\n                \r\n    \/\/ Using named syntax as well as predefined name\r\n    Console.WriteLine($\"a: {r.a}, b: {r.Item2}\");\r\n}<\/pre>\n<p>(*) <code>System.ValueTuple<\/code> types are introduced in .NET Framework 4.7. But you still can use the feature and target lower framework versions, in this case, you have to reference a special nuget package: <a href=\"https:\/\/www.nuget.org\/packages\/System.ValueTuple\/\">System.ValueTuple<\/a>.<\/p>\n<ul>\n<li>Tuple declaration syntax is similar to function parameter declaration: <code>(Type1 name1, Type2 name2)<\/code>.<\/li>\n<li>Tuple construction syntax is similar to argument construction: <code>(value1, optionalName: value2)<\/code>.<\/li>\n<li>Two tuples with the same element types but with different names are compatible (**): <code>(int a, int b) = (1, 2)<\/code>.<\/li>\n<li>Tuples have value semantic: <code>(1,2).Equals((a: 1, b: 2))<\/code> and <code>(1,2).GetHashCode() == (1,2).GetHashCode()<\/code> are both <code>true<\/code>.<\/li>\n<li>Tuples do not support <code>==<\/code> and <code>!=<\/code>. There is a pending discussion about it on github: <a href=\"https:\/\/github.com\/dotnet\/csharplang\/issues\/190\">&#8220;Support for == and != on tuple types&#8221;<\/a>.<\/li>\n<li>Tuples can be &#8220;deconstructed&#8221; but only into &#8220;variable declaration&#8221; but not into &#8220;out var&#8221; or in the <code>case<\/code> block: <code>var (x, y) = (1,2)<\/code> &#8211; OK, <code>(var x, int y) = (1,2)<\/code> &#8211; OK, <code>dictionary.TryGetValue(key, out var (x, y))<\/code> &#8211; not OK, <code>case var (x, y): break;<\/code> &#8211; not OK.<\/li>\n<li>Tuples are mutable: <code>(int a, int b) x (1,2); x.a++;<\/code>.<\/li>\n<li>Tuple elements can be accessed by the name (if provided) or via generic names like <code>Item1<\/code>, <code>Item2<\/code> etc.<\/li>\n<\/ul>\n<p>(**) We&#8217;ll see when this is not the case in a moment.<\/p>\n<h4>Tuple element names<\/h4>\n<p>Lack of user-defined names makes <code>System.Tuple<\/code> types not very useful. I can use <code>System.Tuple<\/code> as an implementation detail of a small method but if I need to pass it around I prefer a named type with descriptive property names. New tuple feature addresses this issue quite elegantly: you can specify names for tuple elements and unlike anonymous classed these names are available even across different assemblies.<\/p>\n<p>The C# compiler emits a special attribute <a href=\"http:\/\/source.roslyn.io\/#System.Runtime\/System.Runtime.cs,3832\"><code>TupleElementNamesAttribute<\/code><\/a>(***) for each tuple type used in a method signature:<\/p>\n<p>(***) The attribute <code>TupleElementNamesAttribute<\/code> is special and can&#8217;t be used directly in the user code. The compiler emits an error if you try to use it.<\/p>\n<pre class=\"lang:default decode:true \">public (int a, int b) Foo1((int c, int d) a) =&gt; a;\r\n\r\n[return: TupleElementNames(new[] { \"a\", \"b\" })]\r\npublic ValueTuple&lt;int, int&gt; Foo(\r\n    [TupleElementNames(new[] { \"c\", \"d\" })] ValueTuple&lt;int, int&gt; a)\r\n{\r\n    return a;\r\n}<\/pre>\n<p>This helps an IDE and the compiler to &#8220;see&#8221; what the element names are and warn if they used incorrectly:<\/p>\n<pre class=\"lang:default decode:true \">\/\/ Ok: tuple literal can skip element names\r\n(int x, int y) tpl = (1, 2);\r\n\r\n\/\/ Warning: The tuple element 'a' is ignored because a different name\r\n\/\/ or no name is specified by the target type '(int x, int y)'.\r\ntpl = (a:1, b:2);\r\n\r\n\/\/ Ok: tuple deconstruction ignore element names\r\nvar (a, b) = tpl;\r\n\r\n\/\/ x: 2, y: 1. Tuple names are ignored\r\nvar (y, x) = tpl;<\/pre>\n<p>The compiler has stronger requirements for inherited members:<\/p>\n<pre class=\"lang:default decode:true \">public abstract class Base\r\n{\r\n    public abstract (int a, int b) Foo();\r\n    public abstract (int, int) Bar();\r\n}\r\n\r\npublic class Derived : Base\r\n{\r\n    \/\/ Error: Cannot change tuple element names when overriding method\r\n    public override (int c, int d) Foo() =&gt; (1, 2);\r\n    \/\/ Error: Cannot change tuple element names when overriding method\r\n    public override (int a, int b) Bar() =&gt; (1, 2);\r\n}<\/pre>\n<p>Regular method arguments can be freely changed in overriden members, tuple element names in overriden members should exactly match ones from a base type.<\/p>\n<h4>Element name inference<\/h4>\n<p>C# 7.1 introduces one additional enhancement: element name inference similar to what C# does for anonymous types.<\/p>\n<pre class=\"lang:default decode:true \">public void NameInference(int x, int y)\r\n{\r\n    \/\/ (int x, int y)\r\n    var tpl = (x, y);\r\n\r\n    var a = new {X = x, Y = y};\r\n\r\n    \/\/ (int X, int y)\r\n    var tpl2 = (a.X, a.Y);\r\n}<\/pre>\n<h4>Value semantic and mutability<\/h4>\n<p>Tuples are mutable value types with elements as public fields. This sounds concerning because we know that mutable value types considered harmful. Here is a small example of their evil nature:<\/p>\n<pre class=\"lang:default decode:true \">var x = new { Items = new List&lt;int&gt; { 1, 2, 3 }.GetEnumerator() };\r\nwhile (x.Items.MoveNext())\r\n{\r\n    Console.WriteLine(x.Items.Current);\r\n}<\/pre>\n<p>If you&#8217;ll run this code you&#8217;ll get &#8230; an infinite loop. <code>List&lt;T&gt;.Enumerator<\/code> is a mutable value type but <code>Items<\/code> is a property. This means that <code>x.Items<\/code> returns a copy of the original iterator on each loop iteration causing an infinite loop.<\/p>\n<p>But mutable value types are dangerous only when the data is mixed with a behavior: an enumerator holds a state (current element) and has a behavior (an ability to advance an iterator by calling <code>MoveNext<\/code> method). This combination can cause issues because it&#8217;s so easy to call a method on a copy instead of on an original instance &#8212; causing effectively no-op. Here is a set of examples that can cause an unobvious behavior due to a hidden copy of a value type: <a href=\"https:\/\/gist.github.com\/SergeyTeplyakov\/8841519120c9858324314e25ddccfc52\">gist<\/a>.<\/p>\n<p>But one issue with mutability still remains:<\/p>\n<pre class=\"lang:default decode:true \">var tpl = (x: 1, y: 2);\r\nvar hs = new HashSet&lt;(int x, int y)&gt;();\r\nhs.Add(tpl);\r\n\r\ntpl.x++;\r\nConsole.WriteLine(hs.Contains(tpl)); \/\/ false<\/pre>\n<p>Tuples are very useful as keys in dictionaries and can be stored in hash sets due to a proper value semantics. But you should not mutate the state of a tuple variable between different operations with the collection.<\/p>\n<h4>Deconstruction<\/h4>\n<p>Even though the tuple construction is special to the tuples, deconstruction is generic and can be used with any type.<\/p>\n<pre class=\"lang:default decode:true \">public static class VersionDeconstrucion\r\n{\r\n    public static void Deconstruct(this Version v, out int major, out int minor, out int build, out int revision)\r\n    {\r\n        major = v.Major;\r\n        minor = v.Minor;\r\n        build = v.Build;\r\n        revision = v.Revision;\r\n    }\r\n}\r\n\r\n\r\nvar version = Version.Parse(\"1.2.3.4\");\r\nvar (major, minor, build, _) = version;\r\n\r\n\/\/ Prints: 1.2.3\r\nConsole.WriteLine($\"{major}.{minor}.{build}\");<\/pre>\n<p>Deconstruction uses &#8220;duck-typing&#8221; approach: if the compiler can find a method called <code>Deconstruct<\/code> for a given type &#8211; instance method or an extension method &#8211; the type is deconstructable.<\/p>\n<h4>Aliasing tuples<\/h4>\n<p>Once you start using the tuples, you&#8217;ll quickly realize that you want to &#8220;reuse&#8221; a tuple type with named elements in multiple places in your source code. But there are few issues with that. First, C# does not support global aliases for a given type. You can use &#8216;using&#8217; alias directive, but it creates an alias visible in one file. And second, you can&#8217;t even alias the tuple:<\/p>\n<pre class=\"lang:default decode:true \">\/\/ You can't do this: compilation error\r\nusing Point = (int x, int y);\r\n\r\n\/\/ But you *can* do this\r\nusing SetOfPoints = System.Collections.Generic.HashSet&lt;(int x, int y)&gt;;<\/pre>\n<p>There is a pending discussion on github at <a href=\"https:\/\/github.com\/dotnet\/csharplang\/issues\/423\">&#8220;Tuple types in using directives&#8221;<\/a>. So if you&#8217;ll find yourself using one tuple type in multiple places you have two options: keep copy-pasting or create a named type.<\/p>\n<h4>What casing for elements should I use?<\/h4>\n<p>Here is an interesting question: what casing rule we should follow for tuple elements? Pascal case like <code>ElementName<\/code> or camel case like <code>elementName<\/code>? On one hand, tuple elements should follow the naming rule for public members (i.e. PascalCase), but on the other hand, tuples are just bags with variables and variables are camel cased.<\/p>\n<p>You may consider using a different naming scheme based on the usage and use <code>PascalCase<\/code> if a tuple is used as an argument or return type of a method and use <code>camelCase<\/code> if a tuple is created locally in the function. But I prefer to use <code>camelCase<\/code> all the time.<\/p>\n<h4>Conclusion<\/h4>\n<p>I&#8217;ve found tuples very useful in my day to day job. I need more than one return value from a function, or I need to put a pair of values into a hashset, or I need to change a dictionary and keep not the one value but two, or the key becomes more complicated and I need to extend it with another &#8220;field&#8221;.<\/p>\n<p>I even use them to avoid closure allocation with methods such a <a href=\"https:\/\/github.com\/dotnet\/corefx\/blob\/afcbd9a5b9e4ecde2db3a69afd093631f1db91c5\/src\/System.Collections.Concurrent\/src\/System\/Collections\/Concurrent\/ConcurrentDictionary.cs#L1010\"><code>ConcurrentDictionary.TryGetOrAdd<\/code><\/a> that now takes an extra argument. And in many cases the state is a tuple as well.<\/p>\n<p>The feature is very useful but I really want to see a few enhancements:<\/p>\n<ol>\n<li>Global aliases: an ability to &#8220;name&#8221; a tuple and use them in the whole assembly (****).<\/li>\n<li>Deconstruct a tuple in the pattern matching: in <code>out var<\/code> and in <code>case var<\/code>.<\/li>\n<li>Use operator <code>==<\/code> for equality comparison.<\/li>\n<\/ol>\n<p>(****) I know that this feature is debatable, but I think it&#8217;ll be very useful. We can wait for record types, but I&#8217;m not sure if the records will be value types or reference types.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>System.Tuple types were introduced in .NET 4.0 with two significant drawbacks: (1) tuple types are classes and (2) there was no language support for constructing\/deconstructing them. To solve these issues, C# 7 introduces new language feature as well as a new family of types (*). Today, if you need to glue together two values to [&hellip;]<\/p>\n","protected":false},"author":4004,"featured_media":37840,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[6699],"tags":[6695],"class_list":["post-1036","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c","tag-seteplia"],"acf":[],"blog_post_summary":"<p>System.Tuple types were introduced in .NET 4.0 with two significant drawbacks: (1) tuple types are classes and (2) there was no language support for constructing\/deconstructing them. To solve these issues, C# 7 introduces new language feature as well as a new family of types (*). Today, if you need to glue together two values to [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/1036","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/users\/4004"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/comments?post=1036"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/1036\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media\/37840"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media?parent=1036"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/categories?post=1036"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/tags?post=1036"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}