Awaitable.FromResult

I have an interface that allows retrieving a value either synchronously or asynchronously.

Because support for being able to retrieve a value asynchronously is very rarely needed, I’d like to add a default implementation for the asynchronous method, that just takes the result of the synchronous method and converts it into an awaitable object.

With a return value of type Task<T> this can be achieved nicely using Task.FromResult:

public interface IValueProvider<T>
{
    T GetValue();
    Task<T> GetValueAsync() => Task.FromResult(GetValue());
}

But if the asynchronous method returns Awaitable<T> instead, there is no equivalent Awaitable.FromResult for me to use.

I can’t simply return GetValue(), because there’s no implicit conversion from T to Awaitable<T>.

I could add the async keyword to the method, but that would generate an unnecessary IAsyncStateMachine during lowering and result in the CS1998 warning - both of which Task.FromResult conveniently avoids:

The most succinct way I could figure out to get the code to compile without any errors or warnings was with this garbage-generating hack:

public interface IValueProvider<T>
{
    T GetValue();
    async Awaitable<T> GetValueAsync() => await Task.FromResult(GetValue());
}

Would be nice to have a method like Awaitable<T> Awaitable.FromResult<T>(T result), an implicit conversion operator from T to Awaitable<T>, or something similar, that could be used to convert an object of type T to Awaitable<T> without any warnings, garbage generation or need to use the async keyword.

3 Likes

Also Awaitable.WhenAll and Awaitable.WhenAny would be great :smile:

2 Likes

Interesting question. I think I have a solution, though I’m not sure how robust it is as the whole Awaitable ecosystem is so convoluted ^^. A class like that might help:

    public class DummyStateMachine<T> : System.Runtime.CompilerServices.IAsyncStateMachine
    {
        public void MoveNext() {             }
        public void SetStateMachine(IAsyncStateMachine stateMachine) { }
        public static Awaitable<T> GetDummy(T aValue)
        {
            var builder = Awaitable.AwaitableAsyncMethodBuilder<T>.Create();
            var statemachine = new DummyStateMachine<T>();
            builder.Start(ref statemachine);
            builder.SetResult(aValue);
            return builder.Task;
        }
    }

In my quick tests this does work in an async method by using

int foobar = await DummyStateMachine<T>.GetDummy(42);

As I said I haven’t tested it thoroughly. I guess you could even cache the dummy statemachine that does nothing in a static field to avoid unnecessary allocations (besides the one you get anyways). Of course for pracitical reasons you probably want to wrap this in a utility class with a generic method

public class Utils
{
    public static Awaitable<T> GetAsyncResult<T>(T aResult) => DummyStateMachine<T>.GetDummy(aResult);
}

So it could be used as

Awaitable<T> GetValueAsync() => Utils.GetAsyncResult(GetValue());

As I said, no guarantees about potential leaks or anything ^^. Also feel free to choose better class and method names when you want to use it.

4 Likes

Oh nice @Bunny83 , you found a way to access the internal Awaitable<T>.SetResultAndRaiseContinuation without any reflection!

I’ve placed that in a utility class like this:

/// <summary>
/// Utility class that can be used to get an <see cref="Awaitable{TResult}"/> that's completed with a specified result.
/// </summary>
public static class AwaitableUtility
{
    /// <summary>
    /// Gets an <see cref="Awaitable{TResult}"/> that's completed with the specified result.
    /// </summary>
    /// <typeparam name="TResult"> The type of the result returned by the awaitable. </typeparam>
    /// <param name="result"> The result to store into the completed awaitable. </param>
    /// <returns> A completed awaitable. </returns>
    public static Awaitable<TResult> FromResult<TResult>(TResult result)
    {
        var nullStateMachine = new NullStateMachine();
        var builder = Awaitable.AwaitableAsyncMethodBuilder<TResult>.Create();
        builder.Start(ref nullStateMachine);
        builder.SetResult(result);
        return builder.Task;
    }

    readonly struct NullStateMachine : IAsyncStateMachine
    {
        public void MoveNext() { }
        public void SetStateMachine(IAsyncStateMachine stateMachine) { }  
    }
}

And now I can improve the asynchronous method to look like this:

public interface IValueProvider<T>
{
    T GetValue();
    Awaitable<T> GetValueAsync() => AwaitableUtility.FromResult(GetValue());
}

So much nicer - thanks a lot!

1 Like

Ahh nice, I didn’t actually realise that the Start method was a generic method so you could actually implement the null state machine as struct. Though mono had some issues in the past with structs implementing interfaces. Though with the generic ref argument I think this should no longer be an issue. Though if additional boxing applies, as I said, I guess you could probably cache the “NullStateMachine” instance as it literally does nothing. That builder internally uses a class to wrap the statemachine anyways. Though it uses a threadsafe pool for those explicit “boxes” (It’s literally called class StateMachineBox<TStateMachine>). Since the class is pooled and the actual statemachine type is a generic field, it should be kinda garbage free. Though still a lot of overhead for just an empty awaitable ^^.

Yeah, I opted go with a struct mostly because the Start method’s parameter had the ref modifier, so it couldn’t be used with a static read-only field directly (nor a read/write field safely). I could have used a local helper variable, but going with a struct felt a bit less convoluted overall.

Nice find, I usually use AwaitableCompletionSource and directly call SetResult and then return the AwaitableCompletionSource.Awaitable property.

The AwaitableAsyncMethodBuilder could have some allocations internally or additional checks, so the AwaitableCompletionSource solution might be a bit less overhead but I did not check the code in detail and I did not run any profiler tests.

1 Like

@R1PFake Another interesting approach, thanks for sharing!

Implementation:

public static class AwaitableUtility
{
    public static Awaitable<TResult> FromResult<TResult>(TResult result)
        => Result<TResult>.From(result);

    static class Result<TResult>
    {
        static readonly AwaitableCompletionSource<TResult> completionSource = new();

        public static Awaitable<TResult> From(TResult result)
        {
            completionSource.SetResult(result);
            var awaitable = completionSource.Awaitable;
            completionSource.Reset();
            return awaitable;
        }
    }
}
1 Like

Consider using an implicit conversion operator from T to Awaitable for a cleaner solution without unnecessary async overhead or code complexity.

I don’t quite get what you mean. He specifically provides an interface that can retrieve a value either synchronously or asynchronously. That’s what the interface provides.

The actual type of the value is irrelevant. So implicit conversions (which can only be implemented in one of the two types you want to convert between) wouldn’t make much sense.

If an implementer of that interface wants or requires an async implementation (web request, database look up, long background thread calculation, whatever) the primary implementation would be the async one returning an Awaitable. In that case the synchronous one would probably just call the async one and busy spin wait until the async request is completed. In this specific case we just have the simple case that an implementation may directly provide a value, so there’s no need for the async. However to be consistent, both implementations should work, that was the point.

1 Like