Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support csharp7 Generalized async return type alternative to TaskInterfaceFactory.Create #3

Closed
binki opened this issue Jan 24, 2018 · 4 comments

Comments

@binki
Copy link
Contributor

binki commented Jan 24, 2018

Starting with csharp7 (regardless of targeted framework), supposedly any type can be used as a return type for an async method as the type is decorated with instructions to the compiler on how to build the type.

https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-7#generalized-async-return-types

It doesn’t really describe how to actually use generalized return types. And I haven’t actually tried it myself yet. Also, my only concern for this possibly not working is there’s a chance the compiler has some (unintentional, I think) inability to support interface (I only know of official examples for struct (ValueTask<TResult>) and class (Task<TResult>)), but that would probably be fixed by roslyn people if that is an issue. Below is what I think I understand so far how this works in csharp7:

  1. Create a class System.Runtime.CompilerServices.AsyncMethodBuilderAttribute internal to the assembly (the compiler just matches the assembly-local type name; this is purposeful to avoid requiring people to use the latest framework or reference external nugets).
  2. Implement the method builder which the compiler will delegate to which builds the actual ITask<TResult> similar to AsyncValueTaskMethodBuilder.
  3. Decorate your type (ITask<TResult> in this case) with your attribute similar to how ValueTuple<TResult> is decorated.

I suspect that the whole “method builder” might end up requiring implementation of some logic which wasn’t needed for ITask<TResult>.

However, if this could be done, it would make implementing ITask<TResult> methods a ton cleaner. I think I am going to play with ITask and see if I can get a working implementation for it in my spare time.

@binki
Copy link
Contributor Author

binki commented Jan 24, 2018

I have verified that generalized return types allow one to write code like this:

[Test]
public async Task TaskInterfaceAsyncMethodBuilderTask()
{
    await TaskInterfaceAsyncMethodBuilderTaskMethodAsync().ConfigureAwait(false);
}

async ITask TaskInterfaceAsyncMethodBuilderTaskMethodAsync()
{
    await Task.Delay(50).ConfigureAwait(false);
}

[Test]
public async Task TaskInterfaceAsyncMethodBuilderResultTask()
{
    var value = await TaskInterfaceAsyncMethodBuilderResultTaskMethodAsync().ConfigureAwait(false);
    Assert.AreEqual(3, value);
}

async ITask<int> TaskInterfaceAsyncMethodBuilderResultTaskMethodAsync()
{
    var results = await Task.WhenAll(
        Enumerable.Range(0, 3).Select(async i =>
        {
            await Task.Delay(i);
            return i;
        }));
    return results.Length;
}

I’m about to submit a PR, but it is quite ugly because I don’t know how to use CodeContracts (and supposedly it doesn’t work with VS-2017/roslyn anyway because roslyn generated IL that is different from the old compilers, causing ccrewrite to fail to do things). Please review it and let me know if I can do things to make it work or if you can get the buildsystem to be compatible with VS-2017 and I can rebase my patches.

binki added a commit to binki/ITask that referenced this issue Jan 24, 2018
@jam40jeff
Copy link
Owner

Thanks for this! I have been meaning to look into this but I also was under the impression that interfaces were not supported. That's great to hear that they are!

I will update AppVeyor to use Visual Studio 2017 to build.

@jam40jeff
Copy link
Owner

Also, I will remove the CodeContracts stuff.

@binki
Copy link
Contributor Author

binki commented Jan 25, 2018

Awesome! Let me know when you're done and I can try to fix my commits/PR. I noticed I messed up the newlines of the README and I probably need to fix the .cs files to follow project newline conventions and license headers, etc. I'll fix that all after you make your changes. Alternatively, feel free to just copy and paste the implementation over—I don't care that much about commits being in my name ;-).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants