{"action":"created","issue":{"url":"https://api.github.com/repos/dotnet/roslyn/issues/11562","repository_url":"https://api.github.com/repos/dotnet/roslyn","labels_url":"https://api.github.com/repos/dotnet/roslyn/issues/11562/labels{/name}","comments_url":"https://api.github.com/repos/dotnet/roslyn/issues/11562/comments","events_url":"https://api.github.com/repos/dotnet/roslyn/issues/11562/events","html_url":"https://github.com/dotnet/roslyn/issues/11562","id":156829703,"number":11562,"title":"Proposal: guard statement","user":{"login":"gafter","id":3804346,"avatar_url":"https://avatars.githubusercontent.com/u/3804346?v=3","gravatar_id":"","url":"https://api.github.com/users/gafter","html_url":"https://github.com/gafter","followers_url":"https://api.github.com/users/gafter/followers","following_url":"https://api.github.com/users/gafter/following{/other_user}","gists_url":"https://api.github.com/users/gafter/gists{/gist_id}","starred_url":"https://api.github.com/users/gafter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gafter/subscriptions","organizations_url":"https://api.github.com/users/gafter/orgs","repos_url":"https://api.github.com/users/gafter/repos","events_url":"https://api.github.com/users/gafter/events{/privacy}","received_events_url":"https://api.github.com/users/gafter/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/dotnet/roslyn/labels/Area-Language%20Design","name":"Area-Language Design","color":"5319e7"},{"url":"https://api.github.com/repos/dotnet/roslyn/labels/Language-C%23","name":"Language-C#","color":"207de5"},{"url":"https://api.github.com/repos/dotnet/roslyn/labels/New%20Language%20Feature%20-%20Out%20Variable%20Declaration","name":"New Language Feature - Out Variable Declaration","color":"bfd4f2"},{"url":"https://api.github.com/repos/dotnet/roslyn/labels/New%20Language%20Feature%20-%20Pattern%20Matching","name":"New Language Feature - Pattern Matching","color":"bfd4f2"},{"url":"https://api.github.com/repos/dotnet/roslyn/labels/New%20Language%20Feature%20-%20Tuples","name":"New Language Feature - Tuples","color":"bfd4f2"}],"state":"open","locked":false,"assignee":{"login":"gafter","id":3804346,"avatar_url":"https://avatars.githubusercontent.com/u/3804346?v=3","gravatar_id":"","url":"https://api.github.com/users/gafter","html_url":"https://github.com/gafter","followers_url":"https://api.github.com/users/gafter/followers","following_url":"https://api.github.com/users/gafter/following{/other_user}","gists_url":"https://api.github.com/users/gafter/gists{/gist_id}","starred_url":"https://api.github.com/users/gafter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gafter/subscriptions","organizations_url":"https://api.github.com/users/gafter/orgs","repos_url":"https://api.github.com/users/gafter/repos","events_url":"https://api.github.com/users/gafter/events{/privacy}","received_events_url":"https://api.github.com/users/gafter/received_events","type":"User","site_admin":false},"milestone":null,"comments":26,"created_at":"2016-05-25T19:22:15Z","updated_at":"2016-06-07T08:02:26Z","closed_at":null,"body":"When reviewing the scoping rules for `out` variables and pattern variables, the LDM discovered that there is sometimes an unfortunate interaction with a pattern of coding that we call the *guard pattern*. The guard pattern is a coding pattern where you test for the exceptional conditions early, handle them, and then bypass the rest of a method by returning, the rest of a loop by continuing, etc. The idea is to not have to deeply nest the \"normal\" control path. You'd write code like this:\r\n\r\n```cs\r\n    int parsedValue;\r\n    if (!int.TryParse(s, out parsedValue))\r\n    {\r\n        // handle or report the problem\r\n        // this block does not complete normally\r\n    }\r\n\r\n    // use parsedValue here\r\n```\r\n\r\nTo take advantage of the `out var` feature, and avoid having to write the type of the `out` variable, you'd like to write\r\n\r\n```cs\r\n    if (!int.TryParse(s, out var parsedValue))\r\n    {\r\n        // handle or report the problem\r\n        return;\r\n    }\r\n\r\n    // use parsedValue here\r\n```\r\n\r\nbut that doesn't work because `parsedValue` isn't in scope in the enclosing statement. Similar issues arise when using pattern-matching:\r\n\r\n```cs\r\n    Tuple<string, int> expression = ...;\r\n    if (!(expression is @(string key, int value))\r\n    {\r\n        // either the tuple was null or the string was null.\r\n        // handle the problem\r\n        continue;\r\n    }\r\n\r\n    // use key, value here\r\n```\r\n\r\n(The `@` here assumes that tuple patterns are preceded by an `@` character)\r\n\r\nbut that doesn't work because `key` and `value` aren't in scope after the `if` statement.\r\n\r\nSwift addresses this category of issue by introducing the `guard` statement. Translating that into the concepts we've been proposing for C# with tuples and pattern-matching, the equivalent construct would be a new kind of *statement*:\r\n\r\n```antlr\r\nstatement\r\n    : guard_statement\r\n    ;\r\nguard_statement\r\n    : 'guard' '(' expression ')' 'else' embedded_statement\r\n    ;\r\n```\r\n\r\n> **Open Issue**: should we require parens around the expression as part of the syntax?\r\n\r\nA `guard` statement is like an inverted if statement, or an if statement without a \"then\" block. It has the following semantics:\r\n\r\n1. The *expression* of a *guard_statement* must be a boolean expression.\r\n2. The *embedded_statement* is reached when the *expression* is `false`.\r\n3. The statement following the *guard_statement* is reached when the *expression* is `true`.\r\n4. The *embedded_statement* may not complete normally.\r\n5. Any *pattern variables* and *out variables* declared in *expression* are in the scope of the block enclosing the *guard_statement*.\r\n\r\nThis would allow you to handle the previous examples as follows:\r\n\r\n```cs\r\n    guard (int.TryParse(s, out var parsedValue))\r\n    else {\r\n        // handle or report the problem\r\n        return;\r\n    }\r\n\r\n    // use parsedValue here\r\n```\r\n\r\n```cs\r\n    Tuple<string, int> expression = ...;\r\n    guard (expression is @(string key, int value))\r\n    else {\r\n        // either the tuple was null or the key was null.\r\n        // handle the problem\r\n        continue;\r\n    }\r\n\r\n    // use key, value here\r\n```\r\n\r\n/cc @dotnet/ldm \r\n"},"comment":{"url":"https://api.github.com/repos/dotnet/roslyn/issues/comments/224208446","html_url":"https://github.com/dotnet/roslyn/issues/11562#issuecomment-224208446","issue_url":"https://api.github.com/repos/dotnet/roslyn/issues/11562","id":224208446,"user":{"login":"Thaina","id":1042507,"avatar_url":"https://avatars.githubusercontent.com/u/1042507?v=3","gravatar_id":"","url":"https://api.github.com/users/Thaina","html_url":"https://github.com/Thaina","followers_url":"https://api.github.com/users/Thaina/followers","following_url":"https://api.github.com/users/Thaina/following{/other_user}","gists_url":"https://api.github.com/users/Thaina/gists{/gist_id}","starred_url":"https://api.github.com/users/Thaina/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Thaina/subscriptions","organizations_url":"https://api.github.com/users/Thaina/orgs","repos_url":"https://api.github.com/users/Thaina/repos","events_url":"https://api.github.com/users/Thaina/events{/privacy}","received_events_url":"https://api.github.com/users/Thaina/received_events","type":"User","site_admin":false},"created_at":"2016-06-07T08:02:26Z","updated_at":"2016-06-07T08:02:26Z","body":"@qrli I think that interesting. But would it be confused in `while` or `switch` block?"}}
{"actor":{"display_login":"Thaina"}}