{"id":20925,"date":"2019-01-24T10:00:30","date_gmt":"2019-01-24T18:00:30","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/dotnet\/?p=20925"},"modified":"2021-05-14T09:16:31","modified_gmt":"2021-05-14T16:16:31","slug":"do-more-with-patterns-in-c-8-0","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/do-more-with-patterns-in-c-8-0\/","title":{"rendered":"Do more with patterns in C# 8.0"},"content":{"rendered":"<h2>Do more with patterns in C# 8.0<\/h2>\n<p>Visual Studio 2019 Preview 2 is out! And with it, a couple more C# 8.0 features are ready for you to try. It&#8217;s mostly about pattern matching, though I&#8217;ll touch on a few other news and changes at the end.<\/p>\n<h2>More patterns in more places<\/h2>\n<p>When C# 7.0 introduced pattern matching we said that we expected to add <em>more<\/em> patterns in <em>more<\/em> places in the future. That time has come! We&#8217;re adding what we call <em>recursive patterns<\/em>, as well as a more compact expression form of <code>switch<\/code> statements called (you guessed it!) <em>switch expressions<\/em>.<\/p>\n<p>Here&#8217;s a simple C# 7.0 example of patterns to start us out:<\/p>\n<pre class=\"lang:default decode:true\">\r\nclass Point\r\n{\r\n    public int X { get; }\r\n    public int Y { get; }\r\n    public Point(int x, int y) =&gt; (X, Y) = (x, y);\r\n    public void Deconstruct(out int x, out int y) =&gt; (x, y) = (X, Y);\r\n}\r\n\r\nstatic string Display(object o)\r\n{\r\n    switch (o)\r\n    {\r\n        case Point p when p.X == 0 &amp;&amp; p.Y == 0:\r\n            return \"origin\";\r\n        case Point p:\r\n            return $\"({p.X}, {p.Y})\";\r\n        default:\r\n            return \"unknown\";\r\n    }\r\n}\r\n<\/pre>\n<h2>Switch expressions<\/h2>\n<p>First, let&#8217;s observe that many <code>switch<\/code> statements really don&#8217;t do much interesting work within the <code>case<\/code> bodies. Often they all just produce a value, either by assigning it to a variable or by returning it (as above). In all those situations, the switch statement is frankly rather clunky. It feels like the 5-decades-old language feature it is, with lots of ceremony.<\/p>\n<p>We decided it was time to add an expression form of <code>switch<\/code>. Here it is, applied to the above example:<\/p>\n<pre class=\"lang:default decode:true\">\r\nstatic string Display(object o)\r\n{\r\n    return o switch\r\n    {\r\n        Point p when p.X == 0 &amp;&amp; p.Y == 0 =&gt; \"origin\",\r\n        Point p                           =&gt; $\"({p.X}, {p.Y})\",\r\n        _                                 =&gt; \"unknown\"\r\n    };\r\n}\r\n<\/pre>\n<p>There are several things here that changed from switch statements. Let&#8217;s list them out:<\/p>\n<ul>\n<li>The <code>switch<\/code> keyword is &#8220;infix&#8221; between the tested value and the <code>{...}<\/code> list of cases. That makes it more compositional with other expressions, and also easier to tell apart visually from a switch statement.<\/li>\n<li>The <code>case<\/code> keyword and the <code>:<\/code> have been replaced with a lambda arrow <code>=&gt;<\/code> for brevity.<\/li>\n<li><code>default<\/code> has been replaced with the <code>_<\/code> discard pattern for brevity.<\/li>\n<li>The bodies are expressions! The result of the selected body becomes the result of the switch expression.<\/li>\n<\/ul>\n<p>Since an expression needs to either have a value or throw an exception, a switch expression that reaches the end without a match will throw an exception. The compiler does a great job of warning you when this may be the case, but will not force you to end all switch expressions with a catch-all: you may know better!<\/p>\n<p>Of course, since our <code>Display<\/code> method now consists of a single return statement, we can simplify it to be expression-bodied:<\/p>\n<pre class=\"lang:default decode:true\">\r\n    static string Display(object o) =&gt; o switch\r\n    {\r\n        Point p when p.X == 0 &amp;&amp; p.Y == 0 =&gt; \"origin\",\r\n        Point p                           =&gt; $\"({p.X}, {p.Y})\",\r\n        _                                 =&gt; \"unknown\"\r\n    };\r\n<\/pre>\n<p>To be honest, I am not sure what formatting guidance we will give here, but it should be clear that this is a lot terser and clearer, especially because the brevity typically allows you to format the switch in a &#8220;tabular&#8221; fashion, as above, with patterns and bodies on the same line, and the <code>=&gt;<\/code>s lined up under each other.<\/p>\n<p>By the way, we plan to allow a trailing comma <code>,<\/code> after the last case in keeping with all the other &#8220;comma-separated lists in curly braces&#8221; in C#, but Preview 2 doesn&#8217;t yet allow that.<\/p>\n<h2>Property patterns<\/h2>\n<p>Speaking of brevity, the patterns are all of a sudden becoming the heaviest elements of the switch expression above! Let&#8217;s do something about that.<\/p>\n<p>Note that the switch expression uses the <em>type pattern<\/em> <code>Point p<\/code> (twice), as well as a <code>when<\/code> clause to add additional conditions for the first <code>case<\/code>.<\/p>\n<p>In C# 8.0 we&#8217;re adding more optional elements to the type pattern, which allows the pattern itself to dig further into the value that&#8217;s being pattern matched. You can make it a <em>property pattern<\/em> by adding <code>{...}<\/code>&#8216;s containing nested patterns to apply to the value&#8217;s accessible properties or fields. This let&#8217;s us rewrite the switch expression as follows:<\/p>\n<pre class=\"lang:default decode:true\">\r\nstatic string Display(object o) =&gt; o switch\r\n{\r\n    Point { X: 0, Y: 0 }         p =&gt; \"origin\",\r\n    Point { X: var x, Y: var y } p =&gt; $\"({x}, {y})\",\r\n    _                              =&gt; \"unknown\"\r\n};\r\n<\/pre>\n<p>Both cases still check that <code>o<\/code> is a <code>Point<\/code>. The first case then applies the constant pattern <code>0<\/code> recursively to the <code>X<\/code> and <code>Y<\/code> properties of <code>p<\/code>, checking whether they have that value. Thus we can eliminate the <code>when<\/code> clause in this and many common cases.<\/p>\n<p>The second case applies the <code>var<\/code> pattern to each of <code>X<\/code> and <code>Y<\/code>. Recall that the <code>var<\/code> pattern in C# 7.0 always succeeds, and simply declares a fresh variable to hold the value. Thus <code>x<\/code> and <code>y<\/code> get to contain the int values of <code>p.X<\/code> and <code>p.Y<\/code>.<\/p>\n<p>We never use <code>p<\/code>, and can in fact omit it here:<\/p>\n<pre class=\"lang:default decode:true\">\r\n    Point { X: 0, Y: 0 }         =&gt; \"origin\",\r\n    Point { X: var x, Y: var y } =&gt; $\"({x}, {y})\",\r\n    _                            =&gt; \"unknown\"\r\n<\/pre>\n<p>One thing that remains true of all type patterns including property patterns, is that they require the value to be non-null. That opens the possibility of the &#8220;empty&#8221; property pattern <code>{ }<\/code> being used as a compact &#8220;not-null&#8221; pattern. E.g. we could replace the fallback case with the following two cases:<\/p>\n<pre class=\"lang:default decode:true\">\r\n    { }                          =&gt; o.ToString(),\r\n    null                         =&gt; \"null\"\r\n<\/pre>\n<p>The <code>{ }<\/code> deals with remaining nonnull objects, and <code>null<\/code> gets the nulls, so the switch is exhaustive and the compiler won&#8217;t complain about values falling through.<\/p>\n<h2>Positional patterns<\/h2>\n<p>The property pattern didn&#8217;t exactly make the second <code>Point<\/code> case <em>shorter<\/em>, and doesn&#8217;t seem worth the trouble there, but there&#8217;s more that can be done.<\/p>\n<p>Note that the <code>Point<\/code> class has a <code>Deconstruct<\/code> method, a so-called <em>deconstructor<\/em>. In C# 7.0, deconstructors allowed a value to be deconstructed on assignment, so that you could write e.g.:<\/p>\n<pre class=\"lang:default decode:true\">\r\n(int x, int y) = GetPoint(); \/\/ split up the Point according to its deconstructor\r\n<\/pre>\n<p>C# 7.0 did not integrate deconstruction with patterns. That changes with <em>positional patterns<\/em> which are an additional way that we are extending type patterns in C# 8.0. If the matched type is a tuple type or has a deconstructor, we can use positional patterns as a compact way of applying recursive patterns without having to name properties:<\/p>\n<pre class=\"lang:default decode:true\">\r\nstatic string Display(object o) =&gt; o switch\r\n{\r\n    Point(0, 0)         =&gt; \"origin\",\r\n    Point(var x, var y) =&gt; $\"({x}, {y})\",\r\n    _                   =&gt; \"unknown\"\r\n};\r\n<\/pre>\n<p>Once the object has been matched as a <code>Point<\/code>, the deconstructor is applied, and the nested patterns are applied to the resulting values.<\/p>\n<p>Deconstructors aren&#8217;t always appropriate. They should only be added to types where it&#8217;s really clear which of the values is which. For a <code>Point<\/code> class, for instance, it&#8217;s safe and intuitive to assume that the first value is <code>X<\/code> and the second is <code>Y<\/code>, so the above switch expression is intuitive and easy to read.<\/p>\n<h2>Tuple patterns<\/h2>\n<p>A very useful special case of positional patterns is when they are applied to tuples. If a switch statement is applied to a tuple expression directly, we even allow the extra set of parentheses to be omitted, as in <code>switch (x, y, z)<\/code> instead of <code>switch ((x, y, z))<\/code>.<\/p>\n<p>Tuple patterns are great for testing multiple pieces of input at the same time. Here is a simple implementation of a state machine:<\/p>\n<pre class=\"lang:default decode:true\">\r\nstatic State ChangeState(State current, Transition transition, bool hasKey) =&gt;\r\n    (current, transition) switch\r\n    {\r\n        (Opened, Close)              =&gt; Closed,\r\n        (Closed, Open)               =&gt; Opened,\r\n        (Closed, Lock)   when hasKey =&gt; Locked,\r\n        (Locked, Unlock) when hasKey =&gt; Closed,\r\n        _ =&gt; throw new InvalidOperationException($\"Invalid transition\")\r\n    };\r\n<\/pre>\n<p>Of course we could opt to include <code>hasKey<\/code> in the switched-on tuple instead of using <code>when<\/code> clauses &#8211; it is really a matter of taste:<\/p>\n<pre class=\"lang:default decode:true\">\r\nstatic State ChangeState(State current, Transition transition, bool hasKey) =&gt;\r\n    (current, transition, hasKey) switch\r\n    {\r\n        (Opened, Close,  _)    =&gt; Closed,\r\n        (Closed, Open,   _)    =&gt; Opened,\r\n        (Closed, Lock,   true) =&gt; Locked,\r\n        (Locked, Unlock, true) =&gt; Closed,\r\n        _ =&gt; throw new InvalidOperationException($\"Invalid transition\")\r\n    };\r\n<\/pre>\n<p>All in all I hope you can see that recursive patterns and switch expressions can lead to clearer and more declarative program logic.<\/p>\n<h2>Other C# 8.0 features in Preview 2<\/h2>\n<p>While the pattern features are the major ones to come online in VS 2019 Preview 2, There are a few smaller ones that I hope you will also find useful and fun. I won&#8217;t go into details here, but just give you a brief description of each.<\/p>\n<h2>Using declarations<\/h2>\n<p>In C#, <code>using<\/code> statements always cause a level of nesting, which can be highly annoying and hurt readability. For the simple cases where you just want a resource to be cleaned up at the end of a scope, you now have <em>using declarations<\/em> instead. Using declarations are simply local variable declarations with a <code>using<\/code> keyword in front, and their contents are disposed at the end of the current statement block. So instead of:<\/p>\n<pre class=\"lang:default decode:true\">\r\nstatic void Main(string[] args)\r\n{\r\n    using (var options = Parse(args))\r\n    {\r\n        if (options[\"verbose\"]) { WriteLine(\"Logging...\"); }\r\n        ...\r\n    } \/\/ options disposed here\r\n}\r\n<\/pre>\n<p>You can simply write<\/p>\n<pre class=\"lang:default decode:true\">\r\nstatic void Main(string[] args)\r\n{\r\n    using var options = Parse(args);\r\n    if (options[\"verbose\"]) { WriteLine(\"Logging...\"); }\r\n\r\n} \/\/ options disposed here\r\n<\/pre>\n<h2>Disposable ref structs<\/h2>\n<p>Ref structs were introduced in C# 7.2, and this is not the place to reiterate their usefulness, but in return they come with some severe limitations, such as not being able to implement interfaces. Ref structs can now be disposable without implementing the <code>IDisposable<\/code> interface, simply by having a <code>Dispose<\/code> method in them.<\/p>\n<h2>Static local functions<\/h2>\n<p>If you want to make sure your local function doesn&#8217;t incur the runtime costs associated with &#8220;capturing&#8221; (referencing) variables from the enclosing scope, you can declare it as <code>static<\/code>. Then the compiler will prevent reference of anything declared in enclosing functions &#8211; except other static local functions!<\/p>\n<h2>Changes since Preview 1<\/h2>\n<p>The main features of Preview 1 were nullable reference types and async streams. Both have evolved a bit in Preview 2, so if you&#8217;ve started using them, the following is good to be aware of.<\/p>\n<h2>Nullable reference types<\/h2>\n<p>We&#8217;ve added more options to control nullable warnings both in source (through <code>#nullable<\/code> and <code>#pragma warning<\/code> directives) and at the project level. We also changed the project file opt-in to <code>&lt;NullableContextOptions&gt;enable&lt;\/NullableContextOptions&gt;<\/code>.<\/p>\n<h2>Async streams<\/h2>\n<p>We changed the shape of the <code>IAsyncEnumerable&lt;T&gt;<\/code> interface the compiler expects! This brings the compiler out of sync with the interface provided in .NET Core 3.0 Preview 1, which can cause you some amount of trouble. However, .NET Core 3.0 Preview 2 is due out shortly, and that brings the interfaces back in sync.<\/p>\n<h2>Have at it!<\/h2>\n<p>As always, we are keen for your feedback! Please play around with the new pattern features in particular. Do you run into brick walls? Is something annoying? What are some cool and useful scenarios you find for them? Hit the feedback button and let us know!<\/p>\n<p>Happy hacking,<\/p>\n<p>Mads Torgersen, design lead for C#<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Do more with patterns in C# 8.0 Visual Studio 2019 Preview 2 is out! And with it, a couple more C# 8.0 features are ready for you to try. It&#8217;s mostly about pattern matching, though I&#8217;ll touch on a few other news and changes at the end. More patterns in more places When C# 7.0 [&hellip;]<\/p>\n","protected":false},"author":1379,"featured_media":21739,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[196,195],"tags":[46,475],"class_list":["post-20925","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet-core","category-dotnet-framework","tag-c","tag-patterns"],"acf":[],"blog_post_summary":"<p>Do more with patterns in C# 8.0 Visual Studio 2019 Preview 2 is out! And with it, a couple more C# 8.0 features are ready for you to try. It&#8217;s mostly about pattern matching, though I&#8217;ll touch on a few other news and changes at the end. More patterns in more places When C# 7.0 [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/20925","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/1379"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=20925"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/20925\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/21739"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=20925"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=20925"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=20925"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}