Dreaming of multiple tasks

I apologise in advance if this post ends up slightly rambly. Unlike the previous entries, this only partly deals with existing features. Instead, it considers how we might like to handle some situations, and where the language and type system thwarts us a little. Most of the code will be incomplete, as producing something realistic and complete is tricky.

Almost everything I’ve written about so far has dealt with the situation where we just want to execute one asynchronous operation at a time. That’s the case which the await keyword makes particularly easy to work with. That’s certainly a useful case, but it’s not the only one. I’m not going to write about that case in this post. (At least, not much.)

At the other extreme, we’ve got the situation where you have a large number of items to deal with, possibly dynamically generated – something like "fetch all the URLs in this list". We may well be able to launch some or even all of those operations in parallel, but we’re likely to use the results as a general collection. We’re doing the same thing with each of multiple inputs. This is data parallelism. I’m not going to write about that in this post either.

This post is about task parallelism. We want to execute multiple tasks in parallel (which may or may not mean using multiple threads – there could be multiple asynchronous web service calls, for example) and get all the results back before we proceed. Some of the tasks may be the same, but in general they’re not.

Describing the sample scenario

To help make everything sound vaguely realistic, I’m going to use a potentially genuine scenario, based on Stack Overflow. I’d like to make it clear that I have no idea how Stack Overflow really works, so please don’t make any assumptions. In particular, we’re only dealing with a very small portion of what’s required to render a single page. Nevertheless, it gives us something to focus on. (This is a situation I’ve found myself in several times at work, but obviously the internal services at Google are confidential, so I can’t start talking about a really real example.)

As part of rendering a Stack Overflow page for a logged in user, let’s suppose we need to:

  • Authenticate the user’s cookie (which gives us the user ID)
  • Find out the preferences for the user (so we know which tags to ignore etc)
  • Find out the user’s current reputation
  • Find out if there have been any recent comments or badges

All of these can be asynchronous operations. The first one needs to be executed before any of the others, but the final three can all be executed in parallel. We need all the results before we can make any more progress.

I’m going to assume an appropriate abstraction which contains the relevant asynchronous methods. Something like this:

public interface IStackService
{
    Task<int?> AuthenticateUserAsync(string cookie);
    Task<UserSettings> GetSettingsAsync(int userId);
    Task<int> GetReputationAsync(int userId);
    Task<RecentActivity> GetRecentActivityAsync(int userId);
}

The simple "single-threaded" implementation

I’ve put "single-threaded" in quotes here, because this may actually run across multiple-threads, but only one operation will be executed at a time. This is really just here for reference – because it’s so easy, and it would be nice to get the same simplicity with more parallelism.

public async Task<Page> RenderPage(Request request) 

    int? maybeUserId = await service.AuthenticateUserAsync(request.Cookie); 
    if (maybeUserId == null
    { 
        return RenderUnauthenticatedPage(); 
    }
    int userId = maybeUserId.Value;
    
    UserSettings settings = await service.GetUserSettingsAsync(userId);
    int reputation = await service.GetReputationAsync(userId);
    RecentActivity activity = await service.GetRecentActivityAsync(userId);

    // Now combine the results and render the page
}

Just to be clear, this is still better than the obvious synchronous equivalent. While those asynchronous calls are executing, we won’t be sat in a blocked thread, taking very little CPU but hogging a decent chunk of stack space. The scheduler will have less work to do. Life will be all flowers and sunshine… except for the latency.

If each of those requests takes about 100ms, it will take 400ms for the whole lot to complete – when it could take just 200ms. We can’t do better than 200ms with the operations we’ve got to work with: we’ve got to get the user ID before we can perform any of the other operations – but we can do all the other three in parallel. Let’s try doing that using the tools we’ve got available to us and no neat tricks, to start with.

Declaring tasks and waiting for them

First, let’s talk about TaskEx.WhenAll(). This is a method provided in the CTP library, and I wouldn’t be surprised to see it move around a bit over time. There are a bunch of overloads for this – some taking multiple Task<TResult> items, and some being more weakly typed. It simply lets you wait for multiple tasks to complete – and because it returns a task itself, we can "await" it in the usual asyncrhonous way. In this case we have to use the weakly typed version, because our tasks are of different types. That’s fine though, because we’re not going to use the result anyway, except for waiting. (And in fact we’ll let the compiler deal with that for us.)

The code for this isn’t too bad, but it’s a bit more long-winded:

public async Task<Page> RenderPage(Request request) 

    int? maybeUserId = await service.AuthenticateUserAsync(request.Cookie); 
    if (maybeUserId == null
    { 
        return RenderUnauthenticatedPage(); 
    }
    int userId = maybeUserId.Value;
    
    var settingsTask = service.GetUserSettingsAsync(userId);
    var reputationTask = service.GetReputationAsync(userId);
    var activityTask = service.GetRecentActivityAsync(userId);
    
    // This overload of WhenAll just returns Task, so there’s no result
    // to wait for: we’ll get the various results from the tasks themselves
    await TaskEx.WhenAll(settingsTask, reputationTask, activityTask);

    // By now we know that the result of each task is available
    UserSettings settings = settingsTask.Result;
    int reputation = reputationTask.Result;
    RecentActivity activity = activityTask.Result;

    // Now combine the results and render the page
}

This is still nicer than the pre-C# 5 code to achieve the same results, but I’d like to think we can do better. Really we just want to express the tasks once, wait for them all to complete, and get the results into variables, just like we did in the one-at-a-time code. I’ve thought of two approaches for this: one using anonymous types, and one using tuples. Both require changes to be viable – although the tuple approach is probably more realistic. Let’s look at it.

EDIT: Just before we do, I’d like to include code from one of the comments. If we’re going to use all the results directly, we can just await them in turn rather than using WhenAll – it’s like joining one thread after another. That leads to code like this:

public async Task<Page> RenderPage(Request request)  
{  
    int? maybeUserId = await service.AuthenticateUserAsync(request.Cookie);  
    if (maybeUserId == null)  
    {  
        return RenderUnauthenticatedPage();  
    } 
    int userId = maybeUserId.Value; 
     
    var settingsTask = service.GetUserSettingsAsync(userId); 
    var reputationTask = service.GetReputationAsync(userId); 
    var activityTask = service.GetRecentActivityAsync(userId); 
     
    UserSettings settings = await settingsTask;
    int reputation = await reputationTask;
    RecentActivity activity = await activityTask;

    // Now combine the results and render the page
}

I definitely like that more. Not sure why I didn’t think of it before…

Now back to the original post…

An ideal world of tuples

I’m assuming you’re aware of the family of System.Tuple types. They were introduced in .NET 4, and are immutable and strongly typed, both of which are nice features. The downsides are that even with type inference they’re still slightly awkward to create, and extracting the component values requires using properties such as Item1, Item2 etc. The C# compiler is completely unaware of tuples, which is slightly annoying. I would like two new features in C# 5:

  • Tuple literals: the ability to write something like var tuple = ("Foo", 10); to create a Tuple<string, int> – I’m not overly bothered with the exact syntax, so long as it’s concise.
  • Assignment to multiple variables from a single tuple. For example: var (ok, value) = int.TryParseToTuple("10");. Assuming a method with signature Tuple<bool, int> TryParseToTuple(string text) this would make ok a variable of type bool, and value a variable of type int.

Just to pre-empt others, I’m aware that F# helps on this front already. C# could do with catching up :)

Anyway, imagine we’ve got those language features. Then imagine a set of extension methods looking like this, but with another overload for 2-value tuples, another for 4-value tuples etc:

public static class TupleExtensions
{
    public static async Task<Tuple<T1, T2, T3>> WhenAll<T1, T2, T3>
        (this Tuple<Task<T1>, Task<T2>, Task<T3>> tasks)
    {
        await TaskEx.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3);
        return Tuple.Create(tasks.Item1.Result, tasks.Item2.Result, tasks.Item3.Result);
    }
}

It can look a bit confusing because of all the type arguments and calls to Result and ItemX properties… but essentially it takes a tuple of tasks, and returns a task of a tuple returning the component values. How does this help us? Well, take a look at our Stack Overflow code now:

public async Task<Page> RenderPage(Request request) 

    int? maybeUserId = await service.AuthenticateUserAsync(request.Cookie); 
    if (maybeUserId == null
    { 
        return RenderUnauthenticatedPage(); 
    }
    int userId = maybeUserId.Value;
    
    var (settings, reputation, activity) = await (service.GetUserSettingsAsync(userId),
                                                  service.GetReputationAsync(userId),
                                                  service.GetRecentActivityAsync(userId))
                                                 .WhenAll();

    // Now combine the results and render the page
}

If we knew we always wanted to wait for all the tasks, we could actually change our extension method to one called GetAwaiter which returned a TupleAwaiter or something like that – so we could get rid of the call to WhenAll completely. However, I’m not sure that would be a good thing. I like explicitly stating how we’re awaiting the completion of all of these tasks.

The real world of tuples

Back in the real world, we don’t have these language features on tuples. We can still use the extension method, but it’s not quite as nice:

public async Task<Page> RenderPage(Request request)  
{  
    int? maybeUserId = await service.AuthenticateUserAsync(request.Cookie);  
    if (maybeUserId == null)  
    {  
        return RenderUnauthenticatedPage();  
    } 
    int userId = maybeUserId.Value; 
     
    var results = await Tuple.Create(service.GetUserSettingsAsync(userId), 
                                     service.GetReputationAsync(userId), 
                                     service.GetRecentActivityAsync(userId)) 
                             .WhenAll(); 

    var settings = results.Item1;
    var reputation = results.Item2;
    var activity = results.Item3;

    // Now combine the results and render the page
}

We’ve got an extra local variable we don’t need, and the ugliness of the ItemX properties is back. Oh well. Maybe tuples aren’t the best approach. Let’s look at a closely related cousin, anonymous types…

An ideal world of anonymous types

Extension methods on anonymous types are somewhat evil. They’re potentially powerful, but they definitely have drawbacks. Aside from anything else, you can’t add a generic constraint to require that a type is anonymous, and you certainly can’t add a generic constraint to say that each member of the anonymous type must be a task (which is what we want here). But the difficulties go further than that. I would like to be able to use something like this:

public async Task<Page> RenderPage(Request request)  
{  
    int? maybeUserId = await service.AuthenticateUserAsync(request.Cookie);  
    if (maybeUserId == null)  
    {  
        return RenderUnauthenticatedPage();  
    } 
    int userId = maybeUserId.Value; 
     
    var results = await new { Settings = service.GetUserSettingsAsync(userId), 
                              Reputation = service.GetReputationAsync(userId), 
                              Activity = service.GetRecentActivityAsync(userId) }
                        .WhenAll(); 

    // Use results.Settings, results.Reputation and results.Activity to render
    // the page
}

Now in this magical world, we’d have an extension method on T where T : class which would check that all the properties were of type Task<TResult> (with a different TResult for each property, potentially) and return a task of a new anonymous type which had the same properties… but without the task part. Essentially, we’re trying to perform the same inversion that we did with tuples, moving where the task "decorator" bit comes. We can’t do that with anonymous types – there’s simply no way of expressing it in the language. We could potentially generate a new type at execution time, but there’s no way of getting compile-time safety.

These two problems suggest two different solutions though. Firstly – and more simply – if we’re happy to lose compile-time safety, we can use the dynamic typing from C# 4.

The real world of anonymous types and dynamic

We can fairly easily write an async extension method to create a Task<dynamic>. The code would involve reflection to extract the tasks from the instance, call TaskEx.WhenAll to wait for them to complete, and then populate an ExpandoObject. I haven’t included the extension method here because frankly reflection code is pretty boring, and the async part of it is what we’ve seen everywhere else. Here’s what the consuming code might look like though:

public async Task<Page> RenderPage(Request request)  
{  
    int? maybeUserId = await service.AuthenticateUserAsync(request.Cookie);  
    if (maybeUserId == null)  
    {  
        return RenderUnauthenticatedPage();  
    } 
    int userId = maybeUserId.Value; 
     
    dynamic results = await new { Settings = service.GetUserSettingsAsync(userId), 
                                  Reputation = service.GetReputationAsync(userId), 
                                  Activity = service.GetRecentActivityAsync(userId) }
                            .WhenAllDynamic(); 

    UserSettings settings = results.Settings;
    int reputation = results.Reputation;
    RecentActivity activity = results.Activity;

    // Use our statically typed variables in the rest of the code
}

The extra local variables are back, because I don’t like being dynamic for more type than I can help. Here, once we’ve copied the results into our local variables, we can ignore the dynamic results variable for the rest of the code.

This is pretty ugly, but it would work. I’m not sure that it’s significantly better than the "works but uses ItemX" tuple version though.

Now, what about the second thought, about the difficulty of translating (Task<X>, Task<Y>) into a Task<(X, Y)>?

Monads

I’m scared. Writing this post has made me start to think I might be starting to grok monads. This is almost certainly an incorrect belief, but I’m sure I’m at least making progress. If we think of "wrapping a task around a type" as a sort of type decoration, it starts sounding similar to the description of monads that I’ve read before. The fact that async workflows in F# are one example of its monad support encourages me too. I have a sneaking suspicion that the async/await support in C# 5 is partial support for this specific monad – in particular, you express the result of an async method via a non-task-related return statement, but the declared return type is the corresponding "wrapped" type.

Now, C#’s major monadic support comes in the form of LINQ, and particularly SelectMany. Therefore – and I’m writing as I think here – I would like to end up being able to write something like this:

public async Task<Page> RenderPage(Request request)  
{  
    int? maybeUserId = await service.AuthenticateUserAsync(request.Cookie);  
    if (maybeUserId == null)  
    {  
        return RenderUnauthenticatedPage();  
    } 
    int userId = maybeUserId.Value; 

    var results = await from settings in service.GetUserSettingsAsync(userId)
                        from reputation in service.GetReputationAsync(userId)
                        from activity in service.GetActivityAsync(userId)
                        select new { settings, reputation, activity };

    // Use results.settings, results.reputation, results.activity for the
    // rest of the code
}

That feels like it should work, but as I write this I genuinely don’t know whether or not it will.

What I do know is that we only actually to write a single method to get that to work: SelectMany. We don’t even need to implement a Select method, as if there’s only a select clause following an extra from clause, the compiler just uses SelectMany and puts a projection at the end. We want to be able to take an existing task and a way of creating a new task from it, and somehow combine them.

Just to make it crystal clear, the way we’re going to use LINQ is not for sequences at all. It’s for tasks. So we don’t want to see IEnumerable<T> anywhere in our final signatures. Let’s see what we can do.

(10 minutes later.) Okay, wow. I’d expected it to be at least somewhat difficult to get it to compile. I’m not quite there yet in terms of parallelization, but I’ve worked out a way round that. Just getting it to work at all is straightforward. I started off by looking at the LINQ to Objects signature used by the compiler:

public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(
    this IEnumerable<TSource> source,
    Func<TSource, IEnumerable<TCollection>> collectionSelector,
    Func<TSource, TCollection, TResult> resultSelector
)

Now we want our tasks to end up being independent, but let’s start off simply, just changing IEnumerable to Task everywhere, and changing the type parameter names:

public static Task<TResult> SelectMany<T1, T2, TResult>(
    this Task<T1> source,
    Func<T1, Task<T2>> taskSelector,
    Func<T1, T2, TResult> resultSelector
)

There’s still that nagging doubt about the dependency of the second task on the first, but let’s at least try to implement it.

We know we want to return a Task<TResult>, and we know that given a T1 and a T2 we can get a TResult. We also know that by writing an async method, we can ask the compiler to go from a return statement involving a TResult to a method with a declared return type of Task<TResult>. Once we’ve got that hint, the rest is really straightforward:

public static async Task<TResult> SelectMany<T1, T2, TResult>
    (this Task<T1> source,
     Func<T1, Task<T2>> taskSelector,
     Func<T1, T2, TResult> resultSelector)
{
    T1 t1 = await source;
    T2 t2 = await taskSelector(t1);
    return resultSelector(t1, t2);
}

There it is. We asynchronously await the result of the first task, feed the result into taskSelector to get the second task, await that task to get a second value, and then combine the two values with the simple projection to give the result we want to return asynchronously.

In monadic terms as copied from Wikipedia, I believe that:

  • The type constructor for the async monad is simply that T goes to Task<T> for any T.
  • The unit function is essentially what the compiler does for us when we declare a method as async – it provides the "wrapping" to get from a return statement using T to a method with a return type of Task<T>.
  • The binding operation is what we’ve got above – which should be no surprise, as SelectMany is the binding function in "normal" LINQ.

I’m breathless with the simultaneous simplicity, beauty and complexity of it all. It’s simple because once I’d worked out the method signature (which is essentially what the definition of the binding function requires) the method wrote itself. It’s beautiful because once I’d picked the right method to use, the compiler did everything else for me – despite it sounding really significantly different to LINQ. It’s complex because I’m still feeling my way through all of this.

It’s a shame that after all of this, we still haven’t actually got what we wanted. To do that, we have to fake it.

Improper monads

("Improper monads" isn’t a real term. It scores 0 hits on Google at the moment – by the time you read this, that count will probably be higher, but only because of this post.)

We wanted to execute the tasks in parallel. We’re not actually doing so. We’re executing one task, then another. Oops. The problem is that our monadic definition says that we’re going to rely on the result of one task to generate the other one. We don’t want to do that. We want to get both tasks, and execute them at the same time.

Unfortunately, I don’t think there’s anything in LINQ which represents that sort of operation. The closest I can think of is a join – but we’re not joining on anything. I’m pretty sure we could do this by implementing InnerJoin and just ignoring the key selectors, but if we’re going to cheat anyway, we might as well cheat with the signature we’ve got. In this cheating version of LINQ, we assume that the task selector (which produces the second task) doesn’t actually rely on the argument it’s given. So let’s just give it anything – the default value, for example. Then we’ve got two tasks which we can await together using WhenAll as before.

public static async Task<TResult> SelectMany<T1, T2, TResult>
    (this Task<T1> task1,
     Func<T1, Task<T2>> taskSelector,
     Func<T1, T2, TResult> resultSelector)
{
    Task<T2> task2 = taskSelector(default(T1));
    await TaskEx.WhenAll(task1, task2);
    return resultSelector(task1.Result, task2.Result);
}

Okay, that was easy. But it looks like it’s only going to wait for two tasks at a time. We’ve got three in our example. What’s going to happen? Well, we’ll start waiting for the first two tasks when SelectMany is first called… but then we’ll return back to the caller with the result as a task. We’ll then call SelectMany again with the third task. We’ll then wait for [tasks 1 and 2] and [task 3]… which means waiting for all of them. Bingo! Admittedly I’ve a sneaking suspicion that if any task fails it might mean more deeply nested exceptions than we’d want, but I haven’t investigated that yet.

I believe that this implementation lets us basically do what we want… but like everything else, it’s ugly in its own way. In this case it’s ugly because it allows us to express something (a dependency from one task to another) that we then don’t honour. I don’t like that. We could express the fact that getting a user’s reputation depends on authenticating the user first – but we’d end up finding the reputation of user 0, because that’s the result we’d pass in. That sucks.

EDIT: Along the same lines of the previous edit, we can make this code neater and avoid using WhenAll:

public static async Task<TResult> SelectMany<T1, T2, TResult> 
    (this Task<T1> task1, 
     Func<T1, Task<T2>> taskSelector, 
     Func<T1, T2, TResult> resultSelector) 

    Task<T2> task2 = taskSelector(default(T1)); 
    return resultSelector(await task1, await task2); 
}

Back to the original post…

Ironically, someone on Twitter mentioned a new term to me today, which seems strikingly relevant: joinads. They pointed to a research paper written by Tomas Petricek and Don Syme – which on first glance is quite possibly exactly what I’ve been mostly-independently coming up with here. The reason LINQ query expressions don’t quite fit what we want is that they’re based on monads – if they’d been based on joinads, maybe it would all have worked well. I’ll read the paper and see if that gives me the answer. Then I’ll watch Bart de Smet’s PDC 2010 presentation which I gather is rather good.

Conclusion

I find myself almost disappointed. Those of you who already understand monads are quite possibly shaking your heads, saying to yourself that it was about time I started to "get" them (and that I’ve got a long way to go). Those of you who didn’t understand them before almost certainly don’t understand them any better now, given the way this post has been written.

So I’m not sure whether I’ll have any readers left by now… and I’ve failed to come up with a good solution to the original problem. In my view the nicest approach by far is the one using tuples, and that requires more language support. (I’m going to nag Mads about that very shortly.) And yet I’m simultaneously on a huge high. I’m very aware of my own limitations when it comes to computer science theory, but today it feels like I’ve at least grasped the edge of something beautiful.

And now, I must stop blogging before my family life falls apart or my head explodes. Goodnight all.

C# 5 async: experimenting with member resolution (GetAwaiter, BeginAwait, EndAwait)

Some of you may remember the bizarre query expressions I’ve come up with before now. These rely on LINQ finding the members it needs (Select, Where, SelectMany etc) statically but without relying on any particular interface. I was pleased to see that the C# 5 async support is based on the same idea. Here’s the relevant bit of the draft spec:

The expression t of an await-expression await t is called the task of the await expression. The task t is required to be awaitable, which means that all of the following must hold:

  • (t).GetAwaiter() is a valid expression of type A.
  • Given an expression a of type A and an expression r of type System.Action, (a).BeginAwait(r) is a valid boolean-expression.
  • Given an expression a of type A, (a).EndAwait() is a valid expression.

A is called the awaiter type for the await expression. The GetAwaiter method is used to obtain an awaiter for the task.

The BeginAwait method is used to sign up a continuation on the awaited task. The continuation passed is the resumption delegate, which is further explained below.

The EndAwait method is used to obtain the outcome of the task once it is complete.

The method calls will be resolved syntactically, so all of GetAwaiter, BeginAwait and EndAwait can be either instance members or extension methods, or even bound dynamically, as long as the calls are valid in the context where the await expression appears. All of them are intended to be “non-blocking”; that is, not cause the calling thread to wait for a significant amount of time, e.g. for an operation to complete.

As far as I can tell, either the CTP release hasn’t fully implemented this, or I’ve interpreted a bit overly broadly. Still, let’s see what works and what doesn’t. For simplicity, each example is completely self-contained… and does absolutely nothing interesting. It’s only the resolution part which is interesting. (The fact that the Main method is async is quite amusing though, and takes advantage of the fact that async methods can return void instead of a task.)

Example 1: Boring instance members

This is closest to the examples I’ve given so far.

using System;

class Test
{
    static async void Main()
    {
        await new Awaitable();
    }
}

class Awaitable
{
    public Awaiter GetAwaiter()
    {
        return new Awaiter();
    }    
}

class Awaiter
{
    public bool BeginAwait(Action continuation)
    {
        return false;
    }
    
    public int EndAwait()
    {
        return 1;
    }
}

Hopefully this needs no further explanation. Obviously it works fine with the CTP. The compiler generates a call to GetAwaiter, then calls BeginAwait and EndAwait on the returned Awaiter.

Example 2: Extension methods

The CTP uses extension methods to get an awaiter for existing types such as Task – but I don’t think it uses them for BeginAwait/EndAwait. Fortunately, there’s nothing to stop us from using them for everything, and there’s nothing forcing you to put the extension methods on sensible types, either – as demonstrated below:

using System;

class Test
{
    static async void Main()
    {
        Guid guid = await 5;
        Console.WriteLine("Got result: {0}", guid);
    }
}

static class Extensions
{
    public static string GetAwaiter(this int number)
    {
        return number.ToString();
    }
    
    public static bool BeginAwait(this string text, Action continuation)
    {
        Console.WriteLine("Waiting for {0} to finish", text);
        return false;
    }
    
    public static Guid EndAwait(this string text)
    {
        Console.WriteLine("Finished waiting for {0}", text);
        return Guid.NewGuid();
    }
}

I should just emphasize that this code is purely for the sake of experimentation. If I ever see anyone actually extending int and string in this way in production code and blaming me for giving them the idea, I’ll be very cross.

However, it all does actually work. This example is silly but not particularly exotic. Let’s start going a bit further, using dynamic typing.

Example 3: Dynamic resolution

The spec explicitly says that the methods can be bound dynamically, so I’d expect this to work:

using System;
using System.Dynamic;

class Test
{
    static async void Main()
    {
        dynamic d = new ExpandoObject();
        d.GetAwaiter = (Func<dynamic>) (() => d);
        d.BeginAwait = (Func<Action, bool>) (action => {
            Console.WriteLine("Awaiting");
            return false;
        });
        d.EndAwait = (Func<string>)(() => "Finished dynamically");

        string result = await d;
        Console.WriteLine("Result: {0}", result);
    }
}

Unfortunately, in the CTP this doesn’t work – it fails at compile time with this error:

Test.cs(16,25): error CS1991: Cannot await ‘dynamic’

All is not lost, however. We may not be able to make GetAwaiter to be called dynamically, but what about BeginAwait/EndAwait? Let’s try again:

using System;
using System.Dynamic;

class DynamicAwaitable
{
    public dynamic GetAwaiter()
    {
        dynamic d = new ExpandoObject();
        d.BeginAwait = (Func<Action, bool>) (action => {
            Console.WriteLine("Awaiting");
            return false;
        });
        d.EndAwait = (Func<string>)(() => "Finished dynamically");
        return d;
    }
}

class Test
{
    static async void Main()
    {
        string result = await new DynamicAwaitable();
        Console.WriteLine("Result: {0}", result);
    }
}

This time we get more errors:

Test.cs(22,25): error CS1061: ‘dynamic’ does not contain a definition for ‘BeginAwait’ and no extension method ‘BeginAwait’ accepting a first argument of type ‘dynamic’ could be found (are you missing a using directive or an assembly reference?)

Test.cs(22,25): error CS1061: ‘dynamic’ does not contain a definition for ‘EndAwait’ and no extension method ‘EndAwait’ accepting a first argument of type ‘dynamic’ could be found (are you missing a using directive or an assembly reference?)

Test.cs(22,25): error CS1986: The ‘await’ operator requires that its operand ‘DynamicAwaitable’ have a suitable public GetAwaiter method

This is actually worse than before: not only is it not working as I’d expect to, but even the error message has a bug. The await operator doesn’t require that its operand has a suitable public GetAwaiter method – it just has to be accessible. At least, that’s the case with the current CTP. In my control flow post for example, the methods were all internal. It’s possible that the error message is by design, and the compiler shouldn’t have allowed that code, of course – but it would seem a little odd.

Okay, so dynamic resolution doesn’t work. Oh well… let’s go back to static typing, but use delegates, fields and properties.

Example 4: Fields and properties of delegate types

This time we’re back to the style of my original "odd query expressions" post, using fields and properties returning delegates instead of methods:

using System;

class FieldAwaiter
{
    public readonly Func<Action, bool> BeginAwait = continuation => false;
    public readonly Func<string> EndAwait = () => "Result from a property";
}

class PropertyAwaitable
{
    public Func<FieldAwaiter> GetAwaiter
    {
        get { return () => new FieldAwaiter(); }
    }
}

class Test
{
    static async void Main()
    {
        string result = await new PropertyAwaitable();
        Console.WriteLine("Result: {0}", result);
    }
}

Again, I believe this should work according to the spec. After all, this block of code compiles with no problems:

var t = new PropertyAwaitable();
var a = (t).GetAwaiter();
bool sync = (a).BeginAwait(() => {});
string result = (a).EndAwait();

Unfortunately, nothing doing. The version using await fails with this error:

Test.cs(21,25): error CS1061: ‘PropertyAwaitable’ does not contain a definition for ‘GetAwaiter’ and no extension method ‘GetAwaiter’ accepting a first argument of type ‘PropertyAwaitable’ could be found (are you missing a using directive or an assembly reference?)

Test.cs(21,25): error CS1986: The ‘await’ operator requires that its operand ‘PropertyAwaitable’ have a suitable public GetAwaiter method

This wasn’t trying truly weird things like awaiting a class name. Oh well :(

Conclusion

Either I’ve misread the spec, or the CTP doesn’t fully comply to it. This should come as no surprise. It’s not a final release or even a beta. However, it’s fun to investigate the limits of what should be valid. The next question is whether the compiler should be changed, or the spec… I can’t immediately think of any really useful patterns involving returning delegates from properties, for example… so is it really worth changing the compiler to allow it?

 

Update (7th November 2010)

On Thursday I spoke to Mads Torgersen and Lucian Wischik about this. Some changes being considered:

  • The C# spec being tightened up to explicitly say that GetAwaiter/BeginAwait/EndAwait have to be methods, at least when statically typed. In other words, the delegate/property version wouldn’t be expected to work.
  • The BeginAwait pattern may be tightened up to require a return type of exactly Boolean or dynamic (rather than the call being "a boolean-expression" which is very slightly more lax)
  • The dynamic version working – this is more complicated in terms of implementation than one might expect

Just to emphasize, these are changes under consideration rather than promises. They seem entirely reasonable to me. (Dynamic binding sounds potentially useful; property/field resolution definitely less so. Making the spec match the implementation is important to me though :)

C# 5 async: investigating control flow

Yes, this has been a busy few days for blog posts. One of the comments on my previous blog post suggested there may be some confusion over how the control flow works with async. It’s always very possible that I’m the one who’s confused, so I thought I’d investigate.

This time I’m not even pretending to come up with a realistic example. As with my previous code, I’m avoiding creating a .NET Task myself, and sticking with my own custom "awaiter" classes. Again, the aim is to give more insight into what the C# compiler is doing for us. I figure other blogs are likely to concentrate on useful patterns and samples – I’m generally better at explaining what’s going on under the hood from a language point of view. That’s easier to achieve when almost everything is laid out in the open, instead of using the built-in Task-related classes.

That’s not to say that Task doesn’t make an appearance at all, however – because the compiler generates one for us. Note in the code below how the return type of DemonstrateControlFlow is Task<int>, whereas the return value is only an int. The compiler uses Task<T> to wrap up the asynchronous operation. As I mentioned before, that’s the one thing the compiler does which actually requires knowledge of the framework.

The aim of the code is purely to demonstrate how control flows. I have a single async method which executes 4 other "possibly asynchronous" operations:

  • The first operation completes synchronously
  • The second operation completes asynchronously, starting a new thread
  • The third operation completes synchronously
  • The fourth operation completes asynchronously
  • The result is then "returned"

At various points in the code I log where we’ve got to and on what thread. In order to execute a "possibly asynchronous" operation, I’m simply calling a method and passing in a string. If the string is null, the operation completes syncrhonously. If the string is non-null, it’s used as the name of a new thread. The BeginAwait method creates the new thread, and returns true to indicate that the operation is completing asynchronously. The new thread waits half a second (to make things clearer) and then executes the continuation passed to BeginAwait. If you remember, that continuation represents "the rest of the method" – the work to do after the asynchronous operation has completed.

Without further ado, here’s the complete code. As is almost always the case with my samples, it’s a console app:

using System;
using System.Threading;
using System.Threading.Tasks;

public class ControlFlow
{
    static void Main()
    {
        Thread.CurrentThread.Name = "Main";
        
        Task<int> task = DemonstrateControlFlow();
        LogThread("Main thread after calling DemonstrateControlFlow");
        
        // Waits for task to complete, then retrieves the result
        int result = task.Result;        
        LogThread("Final result: " + result);
    }
    
    static void LogThread(string message)
    {
        Console.WriteLine("Thread: {0}  Message: {1}",
                          Thread.CurrentThread.Name, message);
    }
    
    static async Task<int> DemonstrateControlFlow()
    {
        LogThread("Start of method");
        
        // Returns synchronously (still on main thread)
        int x = await MaybeReturnAsync(null);        
        LogThread("After first await (synchronous)");
        
        // Returns asynchronously (return task to caller, new
        // thread is started by BeginAwait, and continuation
        // runs on that new thread).
        x += await MaybeReturnAsync("T1");        
        LogThread("After second await (asynchronous)");
        
        // Returns synchronously – so we’re still running on
        // the first extra thread
        x += await MaybeReturnAsync(null);
        LogThread("After third await (synchronous)");
            
        // Returns asynchronously – starts up another new
        // thread, leaving the first extra thread to terminate,
        // and executing the continuation on the second extra thread.
        x += await MaybeReturnAsync("T2");
        LogThread("After fourth await (asynchronous)");
        
        // Sets the result of the task which was returned ages ago;
        // when this occurs, the main thread
        return 5;
    }
    
    /// <summary>
    /// Returns a ResultFetcher which can have GetAwaiter called on it.
    /// If threadName is null, the awaiter will complete synchronously
    /// with a return value of 1. If threadName is not null, the
    /// awaiter will complete asynchronously, starting a new thread
    /// with the given thread name for the continuation. When EndAwait
    /// is called on such an asynchronous waiter, the result will be 2.
    /// </summary>
    static ResultFetcher<int> MaybeReturnAsync(string threadName)
    {
        return new ResultFetcher<int>(threadName, threadName == null ? 1 : 2);
    }
}

/// <summary>
/// Class returned by MaybeReturnAsync; only exists so that the compiler
/// can include a call to GetAwaiter, which returns an Awaiter[T].
/// </summary>
class ResultFetcher<T>
{
    private readonly string threadName;
    private readonly T result;
    
    internal ResultFetcher(string threadName, T result)
    {
        this.threadName = threadName;
        this.result = result;
    }
    
    internal Awaiter<T> GetAwaiter()
    {
        return new Awaiter<T>(threadName, result);
    }
}

/// <summary>
/// Awaiter which actually starts a new thread (or not, depending on its
/// constructor arguments) and supplies the result in EndAwait.
/// </summary>
class Awaiter<T>
{
    private readonly string threadName;
    private readonly T result;
    
    internal Awaiter(string threadName, T result)
    {
        this.threadName = threadName;
        this.result = result;
    }
    
    internal bool BeginAwait(Action continuation)
    {
        // If we haven’t been given the name of a new thread, just complete
        // synchronously.
        if (threadName == null)
        {
            return false;
        }

        // Start a new thread which waits for half a second before executing
        // the supplied continuation.
        Thread thread = new Thread(() =>
        {
            Thread.Sleep(500);
            continuation();
        });
        thread.Name = threadName;
        thread.Start();
        return true;
    }

    /// <summary>
    /// This is called by the async method to retrieve the result of the operation,
    /// whether or not it actually completed synchronously.
    /// </summary>
    internal T EndAwait()
    {
        return result;
    }
}

And here’s the result:

Thread: Main  Message: Start of method
Thread: Main  Message: After first await (synchronous)
Thread: Main  Message: Main thread after calling DemonstrateControlFlow
Thread: T1  Message: After second await (asynchronous)
Thread: T1  Message: After third await (synchronous)
Thread: T2  Message: After fourth await (asynchronous)
Thread: Main  Message: Final result: 5

A few things to note:

  • I’ve used two separate classes for the asynchronous operation: the one returned by the MaybeReturnAsync method (ResultFetcher<T>),  and the Awaiter<T> class returned by ResultFetcher<T>.GetAwaiter(). In the previous blog post I used the same class for both aspects, and GetAwaiter() returned this. It’s not entirely clear to me under what situations a separate awaiter class is desirable. It feels like it should mirror the IEnumerable<T>/IEnumerator<T> reasoning for iterators, but I haven’t thought through the details of that just yet.
  • If a "possibly asynchronous" operation actually completes synchronously, it’s almost as if we didn’t use "await" at all. Note how the "After first await" is logged on the Main thread, and "After third await" is executed on T1 (the same thread as the "After second await" message). I believe there could be some interesting differences if BeginAwait throws an exception, but I’ll investigate that in another post.
  • When the first "properly asynchronous" operation executes, that’s when control is returned to the main thread. It doesn’t have the result yet of course, but it has a task which it can use to find out the result when it’s ready – as well as checking the status and so on.
  • The compiler hasn’t created any threads for us – the only extra threads were created explicitly when we began an asynchronous operation. One possible difference between this code and a real implementation is that MaybeReturnAsync doesn’t actually start the operation itself at all. It creates something which is able to start the operation, but waits until the BeginAwait call before it starts the thread. This made our example easier to write, because it meant we could wait until we knew what the continuation would be before we started the thread.
  • The return statement in our async method basically sets the result in the task. At that point in this particular example, our main thread is blocking, waiting for the result – so it becomes unblocked as soon as the task has completed.

If you’ve been following along with Eric, Anders and Mads, I suspect that none of this is a surprise to you, other than possibly the details of the methods called by the compiler (which are described clearly in the specification). I believe it’s worth working through a simple-but-useless example like this just to convince you that you know what’s going on. If the above isn’t clear – either in terms of what’s going on or why, I’d be happy to draw out a diagram with what’s happening on each thread. As I’m rubbish at drawing, I’ll only do that when someone asks for it.

Next topic: well, what would you like it to be? I know I’ll want to investigate exception handling a bit soon, but if there’s anything else you think I should tackle first, let me know in the comments.

C# 5 async and choosing terminology: why I’m against “yield”

Eric Lippert’s latest (at the time of this writing) blog post asks for suggestions for alternatives to the new "await" keyword, which has inappropriate connotations that confuse people. In particular, it sounds like the thread is going to sit there waiting for the result, when the whole point is that it doesn’t.

There have been many suggestions in the comments, and lots of them involve "yield". I was initially in favour of this too, but on further reflection I don’t think it’s appropriate, for the same reason: it has a connotation which may not be true. It sounds like it’s always going to yield control, when sometimes it doesn’t. To demonstrate this, I’ve come up with a tiny example. It’s a stock market class which allows you to compute the total value of your holdings asynchronously. The class would make web service calls to fetch real prices, but then cache values for some period. The caching bit is the important part here – and in fact it’s the only part I’ve actually implemented.

The point is that when the asynchronous "total value" computation can fetch a price from the cache, it doesn’t need to wait for anything, so it doesn’t need to yield control. This is the purpose of the return value of BeginAwait: if it returns false, the task has been completed and EndAwait can be called immediately. In this case the continuation is ignored – when BeginAwait returns, the ComputeTotalValue method keeps going rather than returning a Task to the caller.

Here’s the complete code:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

class Test
{
    static void Main()
    {
        StockMarket market = new StockMarket();
        market.AddCached("GOOG", 613.70m);
        market.AddCached("MSFT", 26.67m);
        market.AddCached("AAPL", 300.98m);
        
        Task<decimal> total = market.ComputeTotalValueAsync(
            Tuple.Create("AAPL", 10),
            Tuple.Create("GOOG", 20),
            Tuple.Create("MSFT", 25)
        );
        Console.WriteLine("Completed already? {0}", total.IsCompleted);
        Console.WriteLine("Total value: {0}", total.Result);
    }
}

class StockMarket
{
    private readonly Dictionary<string, decimal> cache =
        new Dictionary<string, decimal>();
    
    internal void AddCached(string ticker, decimal price)
    {
        cache[ticker] = price;
    }
    
    public async Task<decimal> ComputeTotalValueAsync(params Tuple<string, int>[] holdings)
    {
        // In real code we may well want to parallelize this, of course
        decimal total = 0m;
        foreach (var pair in holdings)
        {
            total += await new StockFetcher(this, pair.Item1) * pair.Item2;
        }
        Console.WriteLine("Diagnostics: completed ComputeTotalValue");
        return total;
    }
    
    private class StockFetcher
    {
        private readonly StockMarket market;
        private readonly string ticker;
        private decimal value;
        
        internal StockFetcher(StockMarket market, string ticker)
        {
            this.market = market;
            this.ticker = ticker;
        }
        
        internal StockFetcher GetAwaiter()
        {
            return this;
        }
        
        internal bool BeginAwait(Action continuation)
        {
            // If it’s in the cache, we can complete synchronously
            if (market.cache.TryGetValue(ticker, out value))
            {            
                return false;
            }
            // Otherwise, we need to make an async web request and do
            // cunning things. Not implemented :)
            throw new NotImplementedException("Oops.");
        }
        
        internal decimal EndAwait()
        {
            // Usually more appropriate checking here, of course
            return value;
        }
    }
}

(Note that we’d probably have a public method to fetch a single stock value asynchronously too, and that would probably return a task – in this case I wanted to keep everything as simple as possible, not relying on any other implementation of asynchrony. This also shows how the compiler uses GetAwait/BeginAwait/EndAwait… and that they don’t even need to be public methods.)

The result shows that everything was actually computed synchronously – the returned task is complete by the time the method returns. You may be wondering why we’ve bothered using async at all here – and the key is the bit that throws the NotImplementedException. While everything returns synchronously in this case, we’ve allowed for the possibility of asynchronous fetching, and the only bit of code which would need to change is BeginAwait.

So what does this have to do with the choice of keywords? It shows that "yield" really isn’t appropriate here. When the action completes very quickly and synchronously, it isn’t yielding at all.

What’s the alternative?

There are two aspects of the behaviour of the current "await" contextual keyword:

  • We might yield control, returning a task to the caller.
  • We will continue processing at some point after the asynchronous subtask has completed – whether it’s completed immediately or whether our continuation is called back.

It’s hard to capture both of those aspects in one or two words, but I think it make sense to at least capture the aspect which is always valid. So I propose something like "continue after":

foreach (var pair in holdings) 

    total += continue after new StockFetcher(this, pair.Item1) * pair.Item2; 
}

I’m not particularly wedded to the "after" bit – it could be "when" or "with" for example.

I don’t think this is perfect – I’m really just trying to move the debate forward a bit. I think the community doesn’t really have enough of a "feeling" for the new feature yet to come up with a definitive answer at the moment (and I include myself there). I think focusing on which aspects we want to emphasize – with a clear understanding of how the feature actually behaves – it a good start though.

Initial thoughts on C# 5’s async support

As many of you will have seen yesterday, the major new feature of C# 5 was announced yesterday: support for asynchronous operations with new contextual keywords of "async" and "await". I haven’t had a lot of time to play with them yet, but I have a few initial thoughts. Note that these won’t make any sense to you unless you’ve also watched the talk Anders gave, or read Eric’s blog post, or something similar. Links are at the bottom of this post rather than peppered throughout.

Asynchronous != parallel

Do you remember when LINQ was first announced, and there was a huge fear that it was effectively putting SQL into C#, when in fact the truth was more general? Well, it’s the same here. The language feature allows a method to execute asynchronously, but it won’t create new threads and the like automatically.

I suspect there’s going to be a lot of confusion about which parts of the asynchronous model are provided by the language and which by the framework. Obviously I’ll hope to clarify things where I can, but it’s important to understand that the language isn’t going to automatically start extra threads or anything like that.

In the Channel9 PDC interview, Anders stressed this point pretty hard – which suggests he thinks it’s going to cause confusion too. I became a lot more comfortable with what’s going on after reading the draft spec – which is part of the CTP.

Language and framework interaction

It looks like the language changes have been designed to be pattern-based, a little like LINQ and foreach. The async modifier is present more for the sake of developers than the compiler, and the await contextual keyword simply requires a GetAwaiter() method to be available (which can be an extension method); that method has to return something for which BeginAwait(Action) and EndAwait() are valid – and again, these can be extension methods.

One of the tests I performed yesterday was to try to use this myself, with a custom "awaiter factory" – it worked fine, and it’s definitely an interesting way of exploring what’s going on. Expect a blog post along those lines some time next week.

So far, so framework-neutral… the only slight fly in the ointment is the reliance on Task and Task<T>. Just as an iterator block with yield return 10; would usually be declared to return IEnumerable<int>, so an async method ending in return 10; would have a return type of Task<int>. I don’t think that’s actually too bad – but I’ll have to dig into exactly what the language relies on to be completely comfortable with. Are there any aspects of tasks which are usually configured by their factories, for example? If so, what does the compiler do?

My gut feeling is that the language is still keeping the framework at an appropriate distance as far as it can, but that it’s got to have something like Task<T> as a way of representing an asynchronous operation.

But is it any use?

Again, I’m really going on gut feelings so far. I think it’s going to be very useful – and I wish I had something similar in Java when writing internal services at work. I like the fact that it’s relatively simple – it feels much simpler than dynamic typing, for example – so I think I’ll be able to get my head round it.

It’s important to note that it’s not a free lunch, and doesn’t try to be. It removes much of the error-prone mechanical drudgery of writing asynchronous code, but it doesn’t attempt to magically parallelize everything you do. You still need to think about what makes sense to do asynchronously, and how to introduce parallelism where appropriate. That’s a really good thing, in my view: it’s about managing complexity rather than hiding it.

Conclusion

I think C# 5 is going to be a lot of fun… but I also think you’re going to need to understand the Task Parallel Library to really make the most of it. Keep the two separate in your head, and understand how they complement each other. If ever there was a good time to learn TPL thoroughly, it’s now. Learning the C# 5 features themselves won’t take long. Mastering the combination of the two in a practical way could be a much bigger task.

Links

Obviously there are lots of resources flooding out of Microsoft (and other bloggers) at the moment. Here are a few to start with:

  • The Visual Studio async home – probably the best site to bookmark, as I’m sure it’ll get updated over time. Download the CTP from here, as well as watching various videos.
  • PDC 2010 player – as this was announced at PDC, there are lots of talks there, including the session where Anders introduces the feature.
  • Eric Lippert’s first blog post on async – with more to come, of course. Follow the Async or C# 5.0 tags.
  • A blog post by Michael Crump with a CTP walkthrough

Overloading and generic constraints

A recent Stack Overflow question piqued my interest. It looked like some inappropriate methods were being considered in overload resolution, when I thought they should have been rejected earlier. Yet again, I thought I’d found a compiler bug, but it turned out to be a case of misreading the spec. I’m arrogant enough to think that if I misread the spec, someone else might too, so I thought I’d dig into it a bit.

It turns out that Eric Lippert has written about the same area of the spec, but in the more complicated scenario where type inference is involved – in other words, where the compiler is working out what generic type arguments should be supplied to a method. While that’s certainly interesting, type inference introduces a whole extra bit of the spec which I prefer to avoid for reasons of health. We can still explore the same key process without involving type inference. I’m effectively revisiting one small part of Eric’s blog post – as much to make sure that I understand it as much as anything else.

The relevant area of the C# 4 spec is section 7.6.5.1, "Method invocations". Broadly speaking, this defines the process for choosing which method to invoke as:

  1. Find a set of candidate methods
  2. Remove methods which aren’t in the most derived type. This is one of the strange areas of overloading which can easily cause surprise. I’ve talked about it elsewhere, particularly in my article on overloading.
  3. If we haven’t found anything else, resort to extension methods
  4. Pick the best method out of the set
  5. Validate that the best method is actually sane

Let’s look at this in three different contexts.

Example 1: Ambiguity

Now, for the purposes of this post I’m only interested in where generic type parameter constraints are checked, and the effects of that on the overall process. Let’s look at a concrete example:

using System;

class Test
{
    static void Foo<T>(string x) where T : struct
    {}
    
    static void Foo<T>(Exception e) where T : class
    {}
    
    static void Main()
    { 
        Foo<object>(null);
    }
}

Okay, so we’ve got two methods called M with different constraints. I’ve given them both parameters of different reference types. Without the parameters, we couldn’t even declare the two methods, as they would have the same signature: the declarations only differ in generic constraints, and constraints aren’t part of the signature. Both parameter types are reference types, so the argument we’re passing (null) is valid for both parameters.

So, what happens when we try to call Foo<object>(null)? Intuitively we might expect it to call the second overload, with the Exception parameter – because that has a constraint on T which is satisfied by the type argument, whereas the first overload has a value type constraint on T, which clearly isn’t satisfied by object. But what happens in the spec?

Well, as per the list above, we first need to find the set of candidate methods. This is where I got confused. Working out the method group is easy – both methods are in it. We’ve supplied type arguments, and both methods are generic, so this bit of the spec applies:

If F is generic and M includes a type argument list, F is a candidate when:

  • F has the same number of method type parameters as were supplied in the type argument list, and
  • Once the type arguments are substituted for the corresponding method type parameters, all constructed types in the parameter list of F satisfy their constraints (§4.4.4), and the parameter list of F is applicable with respect to A (§7.5.3.1).

Note that here, "F" is the method under consideration, and "M" is the invocation expression.

The first bullet is fine: we have a single type argument, and both methods have a single type parameter. So what about the second? It talks about types satisfying constraints, so at first glance you might expect this to rule out the first overload. That’s certainly what I thought initially. But look carefully… it’s talking about the types in the parameter list – checking that they satisfy their constraints. It’s not talking about the type arguments for the method itself, or the constraints there.

Now our two parameters (string and Exception) are both nongeneric, so they can’t even have constraints. Both end up being candidate methods, and because neither is better than the other with respect to our invocation, the call ends up being ambiguous:

Test.cs(13,9): error CS0121: The call is ambiguous between the following methods or properties: ‘Test.Foo<object>(string)’ and ‘Test.Foo<object>(System.Exception)’

The next obvious question is what situation the constraint checking here does have an effect. Let’s look at a very slightly different example.

Example 2: Weeding out invalid constructed parameter types

This time I’m going to introduce an extra generic type. It’s called Factory, and TItem is constrained to have a parameterless constructor. I’ve called it TItem rather than just T for the sake of clarity later on. We’re not going to give it any behaviour, as we’re just interested in the type declaration. Here’s the complete code for the example:

using System; 

class Factory<TItem> where TItem : new()
{}
    
class Test 

    static void Foo<T>(Factory<T> factory) where T : struct
    {} 
     
    static void Foo<T>(Exception e) where T : class 
    {} 
     
    static void Main() 
    {  
        Foo<string>(null);
    }
}

Now, the first thing to note is that just to declare the first method with a parameter of Factory<T>, we have to ensure that T will have a parameterless constructor. That’s coverted by the constraint of T : struct, fortunately.

Now let’s look at the method invocation. This time we’re trying to use string as the type argument. The second method is obviously a candidate – it’s fine in every way. But what about the first?

After type argument substitution, the parameter list for the first method looks like this:

(Factory<string> factory)

Now the spec says that each type in the parameter list has to be valid with respect to its constraints. In this case, it isn’t: string doesn’t have a parameterless constructor, so the type Factory<string> is invalid.

So, the first method is rejected, the second is fine, so it compiles with no problems. The important thing to note is that the compiler hasn’t taken any notice of the where T : struct part of the first method’s declaration… it’s only rejecting the first method on the basis of the constraint on Factory<T>. We can demonstrate that by changing the method invocation:

Foo<object>(null);

Now object does have a parameterless constructor, so the method is still part of the candidate set, and we’re back to the same ambiguous position of our first example.

Now we haven’t yet managed to trip the compiler up on the final part of our list – validating the constraints of method after it’s been chosen.

Example 3: Final validation

I could demonstrate this with a single method, so that overload resolution had no choices to make. However, we’ll have a little bit more fun. Here’s our final sample code:

using System; 

class Test 

    static void Foo<T>(object x) where T : struct
    {} 
     
    static void Foo<T>(string y) where T : class 
    {} 
     
    static void Main() 
    {  
        Foo<int>(null);
    }
}

Gone is Factory<T> – we’re back to simple parameters. The big difference between this example and the first one, however, is that the parameters are object and string instead of string and Exception. That means that although both methods are in the candidate set, the second one is deemed "better" than the first because the conversion from null to string is better (more specific) than the conversion from null to object.

So, the compiler resolves everything about the method invocation without paying any attention to the generic constraints involved until the very last moment – where it notices that the chosen method (the second one) isn’t valid when T is int, and fails with this error:

Test.cs(13,9): error CS0452: The type ‘int’ must be a reference type in order to use it as parameter ‘T’ in the generic type or method ‘Test.Foo<T>(string)’

There’s no mention of ambiguity, because by this point there isn’t any ambiguity. The cruel irony is that if only the compiler had applied the constraints earlier, it would have found that calling the first method is perfectly valid in every way.

Conclusion

I’m not going to try to argue the pros and cons of the way the language has been designed – Eric has some thoughts on that in the blog post, and obviously he has much more insight into the design process than I do. However, next time you find yourself trying to understand why the compiler is behaving in a particular way, hopefully one of these examples may help you.

The curious case of the publicity-seeking interface and the shy abstract class

Noda Time has a guilty secret, and I’m not just talking about the fact that there’s been very little progress on it recently. (It’s not dead as a project – I have high hopes, when I can put some quality time into it.) This secret is called LocalInstant, and it’s a pain in the neck.

One of the nice things about giving talks about an API you’re currently writing is that you can see which concepts make sense to people, and which don’t – as well as seeing which concepts you’re able to explain and which you can’t. LocalInstant has been an awkward type to explain right from day 1, and I don’t think it’s improved much since then. For the purpose of this blog post, you don’t actually need to know what it means, but if you’re really interested, imagine that it’s like a time-zone-less date and time (such as "10:58 on July 2nd 2015" but also missing a calendar system, so you can’t really tell what the month is etc. The important point is that it’s not just time-zone-less, but it’s actually local – so it doesn’t represent a single instant in time. Unlike every other concept in Noda Time, I haven’t thought of any good analogy between LocalInstant and the real world.

Now, I don’t like having types I can’t describe easily, and I’d love to just get rid of it completely… but it’s actually an incredibly powerful concept to have in the library. Not for users of course, but for the implementation. It’s spattered all over the place. Okay, the next best step to removing it is to hide it away from consumers: let’s make it internal. Unfortunately, that doesn’t work either, because it’s referred to in interfaces all the time too. For example, almost every member of ICalendarSystem has LocalInstant as one of its parameters.

The rules around interfaces

Just to recap, every member of an interface – even an internal interface – is implicitly public. That causes some interesting restrictions. Firstly, every type referred to in a public interface must be public. So this would be invalid:

internal struct LocalInstant {}

// Doesn’t compile: Inconsistent accessibility
public interface ICalendarSystem

    LocalInstant GetLocalInstant(int year, int month, int day);
}

So far, so good. It’s entirely reasonable that a public member’s declaration shouldn’t refer to an internal type. Calling code wouldn’t understand what LocalInstant was, so how could it possibly use ICalendarSystem sensibly? But suppose we only wanted to declare the interface internally. That should be okay, right? Indeed, the compiler allows the following code:

internal struct LocalInstant {}

// Compiles with no problems
internal interface ICalendarSystem
{
    LocalInstant GetLocalInstant(int year, int month, int day);
}

But hang on… isn’t GetLocalInstant public? That’s what I said earlier, right? So we’re declaring a public member using an internal type… which we thought wasn’t allowed. Is this a compiler bug?

Well, no. My earlier claim that "a public member’s declaration shouldn’t refer to an internal type" isn’t nearly precise enough. The important aspect isn’t just whether the member is declared public – but its accessibility domain. In this case, the accessibility domain of ICalendarSystem.GetLocalInstant is only the assembly, which is why it’s a valid declaration.

However, life becomes fun when we try to implement ICalendarSystem in a public class. It’s perfectly valid for a public class to implement an internal interface, but we have some problems declaring the method implementing GetLocalInstant. We can’t make it a public method, because at that point its accessibility domain would be anything referring to the assembly, but the accessibility domain of LocalInstant itself would still only be the assembly. We can’t make it internal, because it’s implementing an interface member, which is public.

There is an alternative though: explicit interface implementation. That comes with all kinds of other interesting points, but it does at least compile:

internal struct LocalInstant {}

internal interface ICalendarSystem
{
    LocalInstant GetLocalInstant(int year, int month, int day);
}

public class GregorianCalendarSystem : ICalendarSystem
{
    // Has to be implemented explicitly
    LocalInstant ICalendarSystem.GetLocalInstant(int year, int month, int day);
    {
        // Implementation
    }
}

So, we’ve got somewhere at this point. We’ve managed to make a type used within an interface internal, but at the cost of making the interface itself internal, and requiring explicit interface implementation within any public classes implementing the interface.

That could potentially be useful in Noda Time, but it doesn’t solve our real LocalInstant / ICalendarSystem problem. We need ICalendarSystem to be public, because consumers need to be able to specify a calendar when they create an instance of ZonedDateTime or something similar. Interfaces are just too demanding in terms of publicity.

Fortunately, we have another option up our sleeves…

Abstract classes to the rescue!

I should come clean at this point and say that generally speaking, I’m an interface weenie. Whenever I need a reusable and testable abstraction, I reach for interfaces by default. I have a general bias against concrete inheritance, including abstract classes. I’m probably a little too harsh on them though… particularly as in this case they do everything I need them to.

In Noda Time, I definitely don’t need the ability to implement ICalendarSystem and derive from another concrete class… so making it a purely abstract class will be okay in those terms. Let’s see what happens when we try:

internal struct LocalInstant {} 

public abstract class CalendarSystem

    internal abstract LocalInstant GetLocalInstant(int year, int month, int day);

internal class GregorianCalendarSystem : CalendarSystem
{  
    internal override LocalInstant GetLocalInstant(int year, int month, int day)
    { 
        // Implementation
    } 
}

Hoorah! Now we’ve hidden away LocalInstant but left CalendarSystem public, just as we wanted to. We could make GregorianCalendarSystem public or not, as we felt like it. If we want to make any of CalendarSystem‘s abstract methods public, then we can do so provided they don’t require any internal types. There’s on interesting point though: types outside the assembly can’t derive from CalendarSystem. It’s a little bit as if the class only provided an internal constructor, but with a little bit more of an air of mystery… you can override every method you can actually see, and still get a compile-time error message like this:

OutsideCalendar.cs(1,14): error CS0534: ‘OutsideCalendar’ does not implement inherited abstract member
        ‘CalendarSystem.GetLocalInstant(int, int, int)’

I can just imagine the author of the other assembly thinking, "But I can’t even see that method! What is it? Where is it coming from?" Certainly a case where the documentation needs to be clear. Whereas it’s impossible to create an interface which is visible to the outside world but can’t be implemented externally, that’s precisely the situation we’ve reached here.

The abstract class is a little bit like an authentication token given by a single-sign-on system. From the outside, it’s an opaque item: you don’t know what’s in it or how it does its job… all you know is that you need to obtain it, and then you can use it to do other things. On the inside, it’s much richer – full of useful data and members.

Conclusion

Until recently, I hadn’t thought of using abstract classes like this. It would possibly be nice if we could use interfaces in the same way, effectively limiting the implementation to be in the declaring assembly, but letting the interface itself (and some members) be visible externally.

A bigger question is whether this is a good idea in terms of design anyway. If I do make LocalInstant internal, there will be a lot of interfaces which go the same way… or become completely internal. For example, the whole "fields" API of Noda Time could become an implementation detail, with suitable helper methods to fetch things like "how many days are there in the given month." The fields API is an elegant overall design, but it’s quite complicated considering the very limited situations in which most callers will use it.

I suspect I will try to go for this "reduced API" for v1, knowing that we can always make things more public later on… that way we give ourselves a bit more flexibility in terms of not having to get everything right first time within those APIs, too.

Part of me still feels uncomfortable with the level of hiding involved – I know other developers I respect deeply who hide as little as possible, for maximum flexibility – but I do like the idea of an API which is really simple to browse.

Aside from the concrete use case of Noda Time, this has proved an interesting exercise in terms of revisiting accessibility and the rules on what C# allows.