{"action":"created","issue":{"url":"https://api.github.com/repos/dotnet/csharplang/issues/159","repository_url":"https://api.github.com/repos/dotnet/csharplang","labels_url":"https://api.github.com/repos/dotnet/csharplang/issues/159/labels{/name}","comments_url":"https://api.github.com/repos/dotnet/csharplang/issues/159/comments","events_url":"https://api.github.com/repos/dotnet/csharplang/issues/159/events","html_url":"https://github.com/dotnet/csharplang/issues/159","id":209249805,"number":159,"title":"Proposal:  Support out/pattern variables in LINQ with query-scoping","user":{"login":"HaloFour","id":10102290,"avatar_url":"https://avatars1.githubusercontent.com/u/10102290?v=4","gravatar_id":"","url":"https://api.github.com/users/HaloFour","html_url":"https://github.com/HaloFour","followers_url":"https://api.github.com/users/HaloFour/followers","following_url":"https://api.github.com/users/HaloFour/following{/other_user}","gists_url":"https://api.github.com/users/HaloFour/gists{/gist_id}","starred_url":"https://api.github.com/users/HaloFour/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/HaloFour/subscriptions","organizations_url":"https://api.github.com/users/HaloFour/orgs","repos_url":"https://api.github.com/users/HaloFour/repos","events_url":"https://api.github.com/users/HaloFour/events{/privacy}","received_events_url":"https://api.github.com/users/HaloFour/received_events","type":"User","site_admin":false},"labels":[{"id":537024200,"url":"https://api.github.com/repos/dotnet/csharplang/labels/Discussion","name":"Discussion","color":"c2e0c6","default":false},{"id":545773793,"url":"https://api.github.com/repos/dotnet/csharplang/labels/Feature%20Request","name":"Feature Request","color":"d4c5f9","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":26,"created_at":"2017-02-21T19:35:01Z","updated_at":"2018-03-29T16:25:53Z","closed_at":null,"author_association":"CONTRIBUTOR","body":"See https://github.com/dotnet/roslyn/issues/15619\r\n\r\nTL;DR:\r\n\r\nExtend LINQ query syntax to support the use of `out` declarations and variable patterns in queries so that the introduced identifiers are promoted to range variables that may be referenced in subsequent query clauses.  The scope would be identical to how range variables introduced with the `let` clause today.\r\n\r\nExamples:\r\n\r\n```cs\r\nIEnumerable<string> strings = ...;\r\n\r\nvar numbers1 = from value in strings\r\n    where int.TryParse(value, out var number)\r\n    select number;\r\n\r\nIEnumerable<object> objects = ...;\r\n\r\nvar numbers2 = from value in objects\r\n    where value is int number || (value is string s && int.TryParse(s, out number))\r\n    select number;\r\n```\r\n\r\nSuggested translations, using anonymous types:\r\n\r\n**let**:\r\n```cs\r\nfrom s in strings\r\nlet res = int.TryParse(s, out var i)\r\nwhere res\r\nselect i;\r\n\r\n// translated into:\r\nstrings.Select(s => new { res = int.TryParse(s, out var i), i = i))\r\n    .Where($projected => $projected.res)\r\n    .Select($projected => $projected.i);\r\n```\r\n\r\n**where**:\r\n```cs\r\nfrom s in strings\r\nwhere int.TryParse(s, out var i)\r\nselect i;\r\n\r\n// translated into:\r\nstrings.Select(s => new { $condition = int.TryParse(s, out var i), i = i))\r\n    .Where($projected => $projected.$condition)\r\n    .Select($projected => $projected.i);\r\n```\r\n\r\n**from**:\r\n```cs\r\nfrom department in departments\r\nfrom employee in department.GetEmployees(out var manager)\r\nselect new { employee, manager };\r\n\r\n// translated into:\r\ndepartments.Select(department => new {\r\n        department = department,\r\n        $collection = department.GetEmployees(out var manager),\r\n        manager = manager\r\n    })\r\n    .SelectMany($projected => $projected.$collection,\r\n        ($projected, $collection) => new {\r\n             employee = $projected.employee,\r\n             manager = $projected.manager\r\n        }\r\n    );\r\n```"},"comment":{"url":"https://api.github.com/repos/dotnet/csharplang/issues/comments/377291863","html_url":"https://github.com/dotnet/csharplang/issues/159#issuecomment-377291863","issue_url":"https://api.github.com/repos/dotnet/csharplang/issues/159","id":377291863,"user":{"login":"svick","id":287848,"avatar_url":"https://avatars3.githubusercontent.com/u/287848?v=4","gravatar_id":"","url":"https://api.github.com/users/svick","html_url":"https://github.com/svick","followers_url":"https://api.github.com/users/svick/followers","following_url":"https://api.github.com/users/svick/following{/other_user}","gists_url":"https://api.github.com/users/svick/gists{/gist_id}","starred_url":"https://api.github.com/users/svick/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/svick/subscriptions","organizations_url":"https://api.github.com/users/svick/orgs","repos_url":"https://api.github.com/users/svick/repos","events_url":"https://api.github.com/users/svick/events{/privacy}","received_events_url":"https://api.github.com/users/svick/received_events","type":"User","site_admin":false},"created_at":"2018-03-29T16:25:53Z","updated_at":"2018-03-29T16:25:53Z","author_association":"CONTRIBUTOR","body":"@gafter \r\n\r\nThank you for the review.\r\n\r\n> You wrote\r\n>\r\n>>    When a transparent identifier is checked to be not equal with null, the associated anonymous type object is checked to be not equal with null.\r\n>\r\n> What associated anonymous type object?\r\n\r\nI wanted to explain that `.Where(* => * != null)` should be translated into `.Where(y => y != null)`. The above is my attempt to use the existing framework of transparent identifiers for that, but it's true that it's not well specified. I have changed the translation, so it doesn't use transparent identifier for this purpose any more.\r\n\r\n> In this sense, your proposed specification doesn't even make sense in the flow of the specification. It proposes a syntactic translation, but then throws in definite assignment as a decision criterion. We don't know how definite assignment works until we know what variables are in which scope, so we know what the names refer to, but we won't know any of that until we decide which syntactic translation we're using.\r\n\r\nI have written [a version of the spec](https://gist.github.com/svick/1c321693f32078db9a002d064db77410/08636e073a3cdb91c44c52e10cac2597bfffb4c7) that changes the translation based on whether the type of the expression in `where` is `bool` or not. But if I understand what you said above correctly, that wouldn't work either.\r\n\r\nSo I have updated the specification to always use the same translation for `where` with promoted expression variables. It means it won't work well for types other than `bool`, but I don't know how to write it in a way that supports both variables that are \"definitely assigned after true\" and types other than `bool`, if I can't use semantic information to differentiate the two cases.\r\n\r\n@HaloFour \r\n\r\n> So, if I understand correctly, `from x in a where x is int i select i` becomes\r\n>\r\n> ```c#\r\n> a.Select(x => x is int i ? new{x, i} : null).Where(t => t != null).Select(t => t.i);\r\n> ```\r\n\r\nCorrect.\r\n\r\n> There is no guarantee that Where ensures `t != null` is true.\r\n\r\nYes, but in that case, there is no possible value to give to `i` (except maybe `default`). This means such code will almost certainly fail at some point and I don't think it matters much at which point it will fail.\r\n\r\n>  But we may need all variables to be definitely assigned there, because you don't usually get those errors until you actually use them (which is what we will end up doing in the final translated code, but not in the source)\r\n>\r\n> ```c#\r\n> from item in list\r\n> where item is int i && (item is int j || item is int k)\r\n> select i;\r\n> ```\r\n\r\nThose other variables are not referenced in following clauses. So they are not \"promoted expression variables\", which means you won't get any errors in that query.\r\n\r\nSo the above query would be translated to:\r\n\r\n```c#\r\nlist\r\n.Select(item => item is int i && (item is int j || item is int k) ? new { item, i } : null)\r\n.Where(t => t != null)\r\n.Select(t => t.i)\r\n```"}}
{"actor":{"display_login":"svick"}}