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

Provide an Async conversion function for structural awaiters #559

Closed
5 of 6 tasks
baronfel opened this issue Apr 12, 2017 · 8 comments
Closed
5 of 6 tasks

Provide an Async conversion function for structural awaiters #559

baronfel opened this issue Apr 12, 2017 · 8 comments

Comments

@baronfel
Copy link
Contributor

baronfel commented Apr 12, 2017

I propose we provide functions on the Async module that provide conversions to Async<T> for so-called structural awaiters, meaning types that have a member GetAwaiter: unit -> #awaiter<T>, where #awaiter is a flexible type representing the following constraints:

  • implements one of INotifyCompletion or ICriticalNotifyCompletion,
  • has a boolean property getter IsCompleted, and
  • has a member GetResult () -> T, where T can be void

This will help with interop situations where C# library developers have rolled custom awaiters instead of using Task and Task<T> derivatives, for example in the Microsoft Bot Framework.

There is a snippet at stackoverflow, but proper code review/hardening would be nice.

Pros and Cons

The advantages of making this adjustment to F# are easier more natural library interop.

The disadvantages of making this adjustment to F# are having to either hand-roll such a function, which may be easy to mess up considering SynchronizationContexts, etc, or accept blocking on GetResult.

Extra informtion

Estimated cost (XS, S, M, L, XL, XXL): S

Affidavit (must be submitted)

Please tick this by placing a cross in the box:

  • This is not a question (e.g. like one you might ask on StackOverflow) and I have searched StackOverflow for discussions of this issue
  • I have searched both open and closed suggestions on this site and believe this is not a duplicate
  • This is not something which has obviously "already been decided" in previous versions of F#. If you're questioning a fundamental design decision that has obviously already been taken (e.g. "Make F# untyped") then please don't submit it.

Please tick all that apply:

  • This is not a breaking change to the F# language design
  • I would be willing to help implement and/or test this
  • I or my company would be willing to help crowdfund F# Software Foundation members to work on this
@baronfel baronfel changed the title Provide an Async function for structural awaiters Provide an Async conversion function for structural awaiters Apr 12, 2017
@baronfel
Copy link
Contributor Author

Additional notes: how would this interact with TaskLike<T> which exist now in C#. These are arbitrary awaitable things that specify a builder that knows how to construct them. Is that proposal a (sub)(super)set of this behavior? see this and that discussion on the roslyn repo for more detail

@dsyme
Copy link
Collaborator

dsyme commented Nov 16, 2017

@baronfel I'd be interested to see a complete proposal and proto implementation for this, with examples of use - the linked example looks a bit thin to get the full idea and practical utility

@dsyme
Copy link
Collaborator

dsyme commented Nov 16, 2017

See also https://github.com/dustinmoris/Giraffe/blob/master/src/Giraffe/Tasks.fs#L266 for a guide for how to do this for the task { ... } computation expression

@baronfel
Copy link
Contributor Author

The task computation expression has moved, and it has a very nice generic binder here: https://github.com/rspeele/TaskBuilder.fs/blob/master/TaskBuilder.fs#L80

This binder seems to replicate the targeting criteria I was mentioning in the submission, and might be worth trying to replicate on async directly (via propagating the continuations)

@jnm2
Copy link

jnm2 commented Jul 19, 2018

or accept blocking on GetResult.

One thing I discovered was that there is no requirement for custom C# awaitables to block in their GetResult implementation. It's not expected in general (unless you know something special about a specific type like TaskAwaiter) that GetResult will even be called unless IsCompleted is true or unless OnCompleted has invoked a continuation. (spec)

To achieve actual blocking until complete awaitables over than TaskAwaiter, something like this is needed (sorry for the C#):

var awaiter = awaitable.GetAwaiter();

if (!awaiter.IsCompleted)
{
    using (var completed = new ManualResetEventSlim())
    {
        awaiter.OnCompleted(completed.Set);
        completed.Wait();
    }
}

var result = awaiter.GetResult();

@dsyme
Copy link
Collaborator

dsyme commented Jun 16, 2022

Note this functionality is available for task { ... }.

@dsyme
Copy link
Collaborator

dsyme commented Jan 9, 2023

I'm thinking we should have a general overloaded Async.Await. See also #840 , which can cover this.

@dsyme dsyme closed this as completed Jan 9, 2023
@abelbraaksma
Copy link
Member

For posterity, this was closed as ‘completed’, and yes, it exists to some extend in task now, but remaining and related issues are in #840, which is still open.

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

No branches or pull requests

4 participants