The corefxlab repository contains library suggestions for corefx which itself is a repository containing the .NET Core foundational libraries. One of the gems hidden among these libraries is ValueTask<T> that was added by Stephen Toub as part of the System.Threading.Tasks.Channels library but may be extremely useful on its own. The full implementation of ValueTask<T> can be found here, but this is an interesting subset of the API:

public struct ValueTask < TResult > { public ValueTask ( TResult result ); public ValueTask ( Task < TResult > task ); public static implicit operator ValueTask < TResult >( Task < TResult > task ); public static implicit operator ValueTask < TResult >( TResult result ); public Task < TResult > AsTask (); public bool IsCompletedSuccessfully { get ; } public TResult Result { get ; } public ValueTaskAwaiter GetAwaiter (); public ValueTaskAwaiter ConfigureAwait ( bool continueOnCapturedContext ); // ... }

I first noticed ValueTask<T> in the API documentation when reviewing the channels PR made to corefxlab. I suggested adding a short explanation which Stephen quickly provided:

“ ValueTask<T> is a discriminated union of a T and a Task<T> , making it allocation-free for ReadAsync<T> to synchronously return a T value it has available (in contrast to using Task.FromResult<T> , which needs to allocate a Task<T> instance). ValueTask<T> is awaitable, so most consumption of instances will be indistinguishable from with a Task<T> .”

ValueTask , being a struct , enables writing async methods that do not allocate memory when they run synchronously without compromising API consistency. Imagine having an interface with a Task returning method. Each class implementing this interface must return a Task even if they happen to execute synchronously (hopefully using Task.FromResult ). You can of course have 2 different methods on the interface, a synchronous one and an async one but this requires 2 different implementations to avoid “sync over async” and “async over sync”.

ValueTask<T> has implicit casts from both T and Task<T> (EDIT: The implicit casts were removed to prepare for arbitrary async returns) and can be awaited by itself which makes it extremely simple to use. Consider this possibly async provider API returning a ValueTask<T> :

interface IHamsterProvider { ValueTask < Hamster > GetHamsterAsync ( string name ); }

This provider interface can be implemented synchronously (for in-memory hamsters) by performing a lookup in a Dictionary and returning the Hamster instance (which is implicitly converted into a ValueTask<Hamster> without any additional allocations):

class LocalHamsterProvider : IHamsterProvider { ConcurrentDictionary < string , Hamster > _dictionary ; // ... public ValueTask < Hamster > GetHamsterAsync ( string name ) { Hamster hamster = _dictionary [ name ]; return hamster ; } }

Or asynchronously (for hamsters stored in MongoDB) by performing an asynchronous query and returning the Task<Hamster> instance (which is implicitly converted into ValueTask<Hamster> as well):

class MongoHamsterProvider : IHamsterProvider { IMongoCollection < Hamster > _collection ; // ... public ValueTask < Hamster > GetHamsterAsync ( string name ) { Task < Hamster > task = _collection . Find ( _ => _ . Name == name ). SingleAsync (); return task ; } }

The consumer of this API can await the ValueTask<Hamster> as if it was a Task<Hamster> without knowing whether it was performed asynchronously or not with the benefit of no added allocations:

Hamster hamster = await Locator . Get < IHamsterProvider >(). GetHamsterAsync ( "bar" );

While this example shows 2 different implementations, one synchronous and the other asynchronous, they could easily be combined. Imagine a provider using a local cache for hamsters and falling back to the DB when needed. The few truly asynchronous calls to GetHamsterAsync would indeed require allocating a Task<Hamster> (which will be implicitly converted to ValueTask<Hamster> ) but the rest would complete synchronously and allocation-free:

class HamsterProvider : IHamsterProvider { ConcurrentDictionary < string , Hamster > _dictionary ; // ... IMongoCollection < Hamster > _collection ; // ... public ValueTask < Hamster > GetHamsterAsync ( string name ) { Hamster hamster ; if ( _dictionary . TryGetValue ( name , out hamster )) { return hamster ; } Task < Hamster > task = _collection . Find ( _ => _ . Name == name ). SingleAsync (); task . ContinueWith ( _ => _dictionary . TryAdd ( _ . Result . Name , _ . Result )); return task ; } }

This kind of “hybrid” use of async-await is very common, since these outbound operations to a data store, remote API, etc. can usually benefit from some kind of caching.