Most of my work this week was on making some improvements to some of my libraries. I did some work on the game too, but nothing worth writing about. :)

The main change I made was to one of the core classes I use for concurrency: Future. The future class is a container that can store a single value, and can only be written to once. You can attach one or more listeners to it that will get invoked once it has a value. The primary advantage of using this class is that it lets you easily perform asynchronous operations without having to deal with locking and most types of race conditions, due to the fact that it’s write-once.

Having a type like Future is extremely useful when dealing with things like disk IO or network operations. But it also turns out to be useful in games – you can use Futures to represent long-lived operations like getting a user’s selection from a menu, finding a path through a level, or loading a texture from disk. Future is also the foundation of the Task primitive in my cooperative multithreading library.

The original interface for the Future class didn’t make use of .NET generics. This meant that it was easy to write general code atop futures – you could write a simple function that would take a list of futures as inputs and return a single future as a result that would become completed once all the inputs were completed, for example. The downside is that you basically didn’t get any type safety, and values were always boxed – a future that contained an integer had to store it as an object, and any time you wanted to retrieve a value from a future, you had to cast it.

This week I decided to try and refactor my code such that Future could utilize .NET generics but still be usable with simple utility functions.

The solution was to create a baseline interface that all Futures implement, and write all the utility functions and libraries using that baseline interface, but expose fully typed generic Futures as return values from functions. Here’s a before and after example:

        public static Future WaitForAll (params Future[] futures) {
            return WaitForX(futures, 1);
        }

        public static Future RunInThread (Func<object> workItem) {
            var thunk = new FuncRunInThreadThunk {
                WorkItem = workItem,
            };
            ThreadPool.QueueUserWorkItem(FutureHelpers.RunInThreadHelper, thunk);
            return thunk.Future;
        }

As you can see, the original code lacks type information, so you have to infer it from usage and do casting everywhere. The upside is that it’s general, but you end up paying for it when you make mistakes about types and have to add explicit casts everywhere.

        public static IFuture WaitForAll (params IFuture[] futures) {
            return WaitForX(futures, 1);
        }

        public static Future<U> RunInThread<U> (Func<U> workItem) {
            var thunk = new FuncRunInThreadThunk<U> {
                WorkItem = workItem,
            };
            ThreadPool.QueueUserWorkItem(FutureHelpers.RunInThreadHelper, thunk);
            return thunk.Future;
        }

In the refactored code, the type information is preserved when going through a utility function like RunInThread – if the function being run in a thread returns a float, the resulting future will also contain a float. This eliminates casting but still preserves generality – since a Future<float> implements IFuture just like a Future<int>, you can use that underlying type when writing utility functions, like WaitForAll (though one downside is that WaitForAll is forced to return an IFuture instead of a future of a specific type, since there’s no easy way to guarantee that all the futures are of a given type.)

Performing this refactoring took lots of individual steps – first, I had to change various code to use IFuture instead of Future, and make minor tweaks in order to keep things functioning and keep tests passing. In some cases I still needed to use Future (one obvious example – you can’t construct an interface, so in that case the real type needed to be used). The largest chunk of work there was updating the handlers for futures – previously, a future listener looked like this:

var handler = (OnComplete) (future, result, error) => { Console.WriteLine("Future {0} completed with result {1}/error {2}", future, result, error); };

The three arguments were mostly an artifact from previous refactorings – originally the Future argument wasn’t there at all. The existence of the result argument was a problem, because it had to be the same type as the future – a Future<float> needed an OnComplete listener that took a float result, which made it difficult to construct generic listeners.

In order to make things simpler, I removed the result and error parameters. Including the future still made it possible to get at the result and error, but allowed the listener to be general by accepting an IFuture instead of a strictly-typed Future<T>. This was important for being able to wire futures up to each other (The WaitForAll function is a good example of this, in that it connects multiple futures to a single result future.)

Once I had updated all the existing listener code, the final step was to add a type argument to Future, and add type information to various library functions.

Here’s an example of the results – if you were writing a Task to do asynchronous reads from a socket or a file, one line at a time, the code to do the read might look like this:

Future f = input.ReadLine();
yield return f;
string line = (f.Result as string);

The ReadLine method of the input stream returns a Future, which will be completed with a string when a line has been successfully read from the stream. The Task yields on the Future to suspend execution until it’s been completed with a result. Once it’s completed, execution resumes, and we pull the resulting line out of the future. It’s obvious that there are some problems with this approach. With the new generic type, the cast is eliminated and ReadLine has a clear return type:

Future<string> f = input.ReadLine();
yield return f;
string line = f.Result;

And if you put C# 3.0′s language features to work, the end result is almost free of duplication:

var f = input.ReadLine();
yield return f;
var line = f.Result;

This is one example where having bidirectional iterators (like in Python) would be beneficial. Python’s yield expression has a result, so you can ‘send’ an input into an iterator every time you advance it. As a result, this code written using a library like imvu.task would look like so:

line = yield input.readLine()

The advantage is pretty obvious – the entire operation is in one line and the meaning is more clear.

Still, this solution is pretty good for C#. You get most of the advantages you could want: Simple code, type safety, thread safety, rock-solid error handling, and scalability. (One of the advantages of using the Future type is that it ensures that you always get either a result or an error. This means that any code that uses a Future to retrieve a result will have exceptions rethrown when an asynchronous operation fails – no need to manage error flags and add lots of try/catch blocks.)

While doing all this refactoring, my large set of unit tests came in handy – they caught a number of bugs I introduced early, and revealed an existing bug that was months old. As a result, I ended up with better error handling, better type safety, and a more robust set of unit tests. On the other hand, I still don’t have any unit tests for my platformer, so maybe I should take another shot at figuring out how to write some for it. (:

If you’re interested in seeing how Future and Task work, you can see the source code and some working examples here:

http://code.google.com/p/fracture/source/browse/#svn/trunk/Squared/TaskLib

I encourage you to check out the repository and try the MUD Server and Telnet Chat examples. They’re not real-world applications, but they’re easy to understand and demonstrate how using Futures and Tasks simplifies concurrency. The MUD even has gameplay! :)