{"action":"created","issue":{"url":"https://api.github.com/repos/dotnet/corefx/issues/32742","repository_url":"https://api.github.com/repos/dotnet/corefx","labels_url":"https://api.github.com/repos/dotnet/corefx/issues/32742/labels{/name}","comments_url":"https://api.github.com/repos/dotnet/corefx/issues/32742/comments","events_url":"https://api.github.com/repos/dotnet/corefx/issues/32742/events","html_url":"https://github.com/dotnet/corefx/issues/32742","id":368714413,"node_id":"MDU6SXNzdWUzNjg3MTQ0MTM=","number":32742,"title":"Proposal: Add IAsyncEnumerable<T> support to System.Threading.Channels","user":{"login":"stephentoub","id":2642209,"node_id":"MDQ6VXNlcjI2NDIyMDk=","avatar_url":"https://avatars0.githubusercontent.com/u/2642209?v=4","gravatar_id":"","url":"https://api.github.com/users/stephentoub","html_url":"https://github.com/stephentoub","followers_url":"https://api.github.com/users/stephentoub/followers","following_url":"https://api.github.com/users/stephentoub/following{/other_user}","gists_url":"https://api.github.com/users/stephentoub/gists{/gist_id}","starred_url":"https://api.github.com/users/stephentoub/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stephentoub/subscriptions","organizations_url":"https://api.github.com/users/stephentoub/orgs","repos_url":"https://api.github.com/users/stephentoub/repos","events_url":"https://api.github.com/users/stephentoub/events{/privacy}","received_events_url":"https://api.github.com/users/stephentoub/received_events","type":"User","site_admin":false},"labels":[{"id":165998434,"node_id":"MDU6TGFiZWwxNjU5OTg0MzQ=","url":"https://api.github.com/repos/dotnet/corefx/labels/api-ready-for-review","name":"api-ready-for-review","color":"5319e7","default":false},{"id":821849498,"node_id":"MDU6TGFiZWw4MjE4NDk0OTg=","url":"https://api.github.com/repos/dotnet/corefx/labels/area-System.Threading.Channels","name":"area-System.Threading.Channels","color":"d4c5f9","default":false}],"state":"open","locked":false,"assignee":{"login":"stephentoub","id":2642209,"node_id":"MDQ6VXNlcjI2NDIyMDk=","avatar_url":"https://avatars0.githubusercontent.com/u/2642209?v=4","gravatar_id":"","url":"https://api.github.com/users/stephentoub","html_url":"https://github.com/stephentoub","followers_url":"https://api.github.com/users/stephentoub/followers","following_url":"https://api.github.com/users/stephentoub/following{/other_user}","gists_url":"https://api.github.com/users/stephentoub/gists{/gist_id}","starred_url":"https://api.github.com/users/stephentoub/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stephentoub/subscriptions","organizations_url":"https://api.github.com/users/stephentoub/orgs","repos_url":"https://api.github.com/users/stephentoub/repos","events_url":"https://api.github.com/users/stephentoub/events{/privacy}","received_events_url":"https://api.github.com/users/stephentoub/received_events","type":"User","site_admin":false},"assignees":[{"login":"stephentoub","id":2642209,"node_id":"MDQ6VXNlcjI2NDIyMDk=","avatar_url":"https://avatars0.githubusercontent.com/u/2642209?v=4","gravatar_id":"","url":"https://api.github.com/users/stephentoub","html_url":"https://github.com/stephentoub","followers_url":"https://api.github.com/users/stephentoub/followers","following_url":"https://api.github.com/users/stephentoub/following{/other_user}","gists_url":"https://api.github.com/users/stephentoub/gists{/gist_id}","starred_url":"https://api.github.com/users/stephentoub/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stephentoub/subscriptions","organizations_url":"https://api.github.com/users/stephentoub/orgs","repos_url":"https://api.github.com/users/stephentoub/repos","events_url":"https://api.github.com/users/stephentoub/events{/privacy}","received_events_url":"https://api.github.com/users/stephentoub/received_events","type":"User","site_admin":false}],"milestone":{"url":"https://api.github.com/repos/dotnet/corefx/milestones/21","html_url":"https://github.com/dotnet/corefx/milestone/21","labels_url":"https://api.github.com/repos/dotnet/corefx/milestones/21/labels","id":3242632,"node_id":"MDk6TWlsZXN0b25lMzI0MjYzMg==","number":21,"title":"3.0","description":".NET Core 3.0, next major release after 2.1. See [official release dates](https://github.com/dotnet/core/blob/master/roadmap.md) for details.\r\n\r\nWe will move important issues from Future to 3.0 as the priorities and dates for next release become more clear.","creator":{"login":"karelz","id":5776068,"node_id":"MDQ6VXNlcjU3NzYwNjg=","avatar_url":"https://avatars2.githubusercontent.com/u/5776068?v=4","gravatar_id":"","url":"https://api.github.com/users/karelz","html_url":"https://github.com/karelz","followers_url":"https://api.github.com/users/karelz/followers","following_url":"https://api.github.com/users/karelz/following{/other_user}","gists_url":"https://api.github.com/users/karelz/gists{/gist_id}","starred_url":"https://api.github.com/users/karelz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/karelz/subscriptions","organizations_url":"https://api.github.com/users/karelz/orgs","repos_url":"https://api.github.com/users/karelz/repos","events_url":"https://api.github.com/users/karelz/events{/privacy}","received_events_url":"https://api.github.com/users/karelz/received_events","type":"User","site_admin":false},"open_issues":283,"closed_issues":2427,"state":"open","created_at":"2018-04-04T16:40:10Z","updated_at":"2018-10-17T20:19:23Z","due_on":null,"closed_at":null},"comments":1,"created_at":"2018-10-10T15:09:41Z","updated_at":"2018-10-18T03:47:20Z","closed_at":null,"author_association":"MEMBER","body":"When we originally prototyped System.Threading.Channels, we included `IAsyncEnumerable<T>` support with a temporary `IAsyncEnumerable<T>` implementation,, but as `IAsyncEnumerable<T>` wasn't actually available when System.Threading.Channels shipped its first release, we cut that support with the idea of adding it back later.  Now that `IAsyncEnumerable<T>` will be available (https://github.com/dotnet/corefx/issues/32640), it's now that \"later\".\r\n\r\n**Proposal**\r\n\r\nAdd the following API:\r\n```C#\r\npublic abstract class ChannelReader<T> // existing type\r\n    : IAsyncEnumerable<T> // new interface implementation\r\n{\r\n    …\r\n    IAsyncEnumerator<T> IAsyncEnumerable<T>.GetAsyncEnumerator(); // for foreach'ing\r\n\r\n    public virtual IAsyncEnumerable<T> AsAsyncEnumerable(CancellationToken cancellationToken = default); // new virtual method\r\n}\r\n```\r\n\r\nThe base implementation will simply provide an async enumerable veneer over the other channel reader methods, e.g.\r\n```C#\r\nIAsyncEnumerator<T> IAsyncEnumerable<T>.GetAsyncEnumerator() =>\r\n    AsAsyncEnumerable().GetEnumerator();\r\n\r\npublic virtual async IAsyncEnumerable<T> AsAsyncEnumerable(CancellationToken cancellationToken = default)\r\n{\r\n    while (await WaitToReadAsync(cancellationToken).ConfigureAwait(false))\r\n    {\r\n        while (TryRead(out T item))\r\n        {\r\n            yield return item;\r\n        }\r\n}\r\n```\r\nbut derived implementations can override to provide a more efficient implementation if applicable.\r\n\r\nWith that, you'll be able to `foreach await` over a channel reader, e.g.\r\n```C#\r\nforeach await (T item in reader)\r\n{\r\n    … // handle each item read from the channel\r\n}\r\n```\r\nor using various extensions on `IAsyncEnumerable<T>`, such as from an async LINQ implementation like that in Ix.NET:\r\n```C#\r\nforeach await (T item in reader.AsAsyncEnumerable(token).WhereAsync(…))\r\n{\r\n    … // handle each filtered item from the channel\r\n}\r\n```\r\n\r\n**Open issues:**\r\n- **Naming.** Developers generally think of enumeration as going through existing data rather than mutating, but `AsAsyncEnumerable()` would produce an async enumerable that does mutate the channel, pulling data out of it.  When we faced that same question with `BlockingCollection<T>`, we chose to use \"consuming\" in the name (`GetConsumingEnumerable`), to highlight that this enumerable actually mutates as it pulls out data.  Should we do the same thing here? e.g. `AsConsumingAsyncEnumerable`?  What about the `As` vs `Get` prefix?\r\n- **Directly implementing `IAsyncEnumerable<T>`**.  This makes it convenient / clean to consume the data from the channel.  Is it too much magic?  Somewhat depends on the above naming question.\r\n\r\n**Notes:**\r\n- **Different builds**. Currently System.Threading.Channels just targets netstandard.  As part of this addition, we'll create a .NET Core-specific build to include in the package, and the additional API will be available when targeting .NET Core."},"comment":{"url":"https://api.github.com/repos/dotnet/corefx/issues/comments/430865924","html_url":"https://github.com/dotnet/corefx/issues/32742#issuecomment-430865924","issue_url":"https://api.github.com/repos/dotnet/corefx/issues/32742","id":430865924,"node_id":"MDEyOklzc3VlQ29tbWVudDQzMDg2NTkyNA==","user":{"login":"electricessence","id":5899455,"node_id":"MDQ6VXNlcjU4OTk0NTU=","avatar_url":"https://avatars1.githubusercontent.com/u/5899455?v=4","gravatar_id":"","url":"https://api.github.com/users/electricessence","html_url":"https://github.com/electricessence","followers_url":"https://api.github.com/users/electricessence/followers","following_url":"https://api.github.com/users/electricessence/following{/other_user}","gists_url":"https://api.github.com/users/electricessence/gists{/gist_id}","starred_url":"https://api.github.com/users/electricessence/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electricessence/subscriptions","organizations_url":"https://api.github.com/users/electricessence/orgs","repos_url":"https://api.github.com/users/electricessence/repos","events_url":"https://api.github.com/users/electricessence/events{/privacy}","received_events_url":"https://api.github.com/users/electricessence/received_events","type":"User","site_admin":false},"created_at":"2018-10-18T03:47:20Z","updated_at":"2018-10-18T03:47:20Z","author_association":"NONE","body":"Was interested in extensions that provided this kind of feature set.  Good?  Bad?\r\n```cs\r\nchannel.Read(item=>{ /* do stuff */ });\r\n```\r\n```cs\r\nchannel.Read(async item=>{ /* do stuff */ await something; });\r\n```\r\n\r\nDidn't want to code a lib just for this purpose if the functionality already existed, and was curious if it seemed futile once async enumerables were available."}}
{"actor":{"display_login":"electricessence"}}