Ayende @ Rahien

Unnatural acts on source code

It's the future now

For various reasons, I had to implement the Future pattern in two completely different settings in three different ways today.

A future is a place-holder for the undetermined result of a (concurrent) computation. Once the computation delivers a result, the associated future is eliminated by globally replacing it with the result value. That value may be a future on its own.

The last implementation was the explicit one, it was simply:

public class Future<T>
{
	private T value;
	private bool hasValue;
	private string error;

	public void SetValue(T value)
	{
		this.value = value;
		hasValue = true;
	}

	public void SetError(string error)
	{
		this.error = error;
	}

	public bool HasError
	{
		get { return error != null; }
	}

	public T Value
	{
		get { return value; }
	}

	public bool HasValue
	{
		get { return hasValue; }
	}

	public string Error
	{
		get { return error; }
	}
}

This is the simplest approach, primitive, you would say. It requires active collaboration from the code that uses it, and it requires that the method would return a future value. It is a good approach for a very small API, but this is often something that you want to handle in a cross cutting fashion. First, we need a more robust future implementation. (This is wasteful in that it doesn't lazily allocate the reset event).

public class Future<T>
{
	private ManualResetEvent resetEvent = new ManualResetEvent(false);
	private T value;
	private bool hasValue;
	private Exception error;

	public void SetValue(T value)
	{
		this.value = value;
		hasValue = true;
		resetEvent.Set();
	}

	public void SetError(Exception error)
	{
		this.error = error;
		resetEvent.Set();
	}

	public bool HasError
	{
		get { return error != null; }
	}

	public T Value
	{
		get
		{
			resetEvent.WaitOne();
			resetEvent.Close();
			if (error != null)
				throw new FutureInvocationException(error);
			return value;
		}
	}

	public bool HasValue
	{
		get { return hasValue; }
	}

	public Exception Error
	{
		get
		{
			resetEvent.WaitOne();
			return error;
		}
	}
}

Now that we have that, we still have to deal with changing the interfaces and an explicitly concurrent programming model. There is a better way, I got the idea from watching a future / active objects implementation in Python, from Ronnie Maor. The ability to subvert the return value there allows for really nice things.

We will start with the easiest version to grasp, we will define the code that we want to work with:

public class WorkFlowController
{
    public virtual int LongRunningTask()
    {
        Console.WriteLine("Starting long running");
        Thread.Sleep(5000);
        Console.WriteLine("Completed long running");
        return 42;
    }
}

Now, we want to make this into something that will return a future, and we want to do it in a way that wouldn't be too awkward. Here is a simple usage:

WorkFlowController controller = new WorkFlowController();
Future<int> future = InThe.Future<int>(delegate { return controller.LongRunningTask(); });
Console.WriteLine("After calling long running");
Console.WriteLine(future.Value);

Executing this code produces:

After calling long runnning
Starting long running
Completed long running
42

The InThe.Future part is simply:

public class InThe
{
    public delegate T Proc<T>();
    public static Future<T> Future<T>(Proc<T> futureAction)
    {
        Future<T> future = new Future<T>();
        ThreadPool.QueueUserWorkItem(delegate
        {
            try
            {
                future.SetValue(futureAction());
            }
            catch (Exception e)
            {
                future.SetError(e);
            }
        });
        return future;
    }
}

This is pretty straightforward, but I don't like the syntax that we have here (even with C# 3.0, it is still ugly). What I would like to get is this:

WorkFlowController controller = With.Future<WorkFlowController>();
Future<int> future = InThe.Future(controller.LongRunningTask());
Console.WriteLine("After calling long runnnig");
Console.WriteLine(future.Value);

Suddenly I have a saner model, and the model to support futures is explicit. The implementation is fairly trivial as well:

public class FutureInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        InThe.lastInvocation = invocation;
        if (invocation.Method.ReturnType.IsValueType)
            invocation.ReturnValue = Activator.CreateInstance(invocation.Method.ReturnType);
    }
}

public static class With
{
    private readonly static ProxyGenerator generator = new ProxyGenerator();

    public static T Future<T>(params object[] args)
    {
        return (T)generator.CreateClassProxy(
            typeof (T), 
            new IInterceptor[] {new FutureInterceptor()}, 
            args);
    }
}

public class InThe
{
    public static IInvocation lastInvocation;

    public static Future<T> Future<T>(T ignored)
    {
        Future<T> future = new Future<T>();
        IInvocation invocation = lastInvocation;
        lastInvocation = null;
        ThreadPool.QueueUserWorkItem(delegate
        {
            try
            {
                invocation.Proceed();
                future.SetValue((T)invocation.ReturnValue);
            }
            catch (Exception e)
            {
                future.SetError(e);
            }
        });
        return future;
    }
}

I like this best, and it is very easy to implement and work with. Return value woes has been overcome, horray!

Comments

Jon Skeet
01/02/2008 09:53 PM by
Jon Skeet

I'm afraid I don't like it, myself. When you call a method as a parameter, normal C# executes the method immediately. I like coding on "solid ground" where the rules of the language don't shift and change.

I guess that's the argument against AOP in general, and normally I'm on AOP's side - this just feels one step too far for my liking.

With C# you could easily have:

Future future = InThe.Future(() => controller.LongRunningTask());

The addition of just 5 characters makes it much obvious that you're passing in a delegate, and that therefore the code may not get executed immediately.

What happens in your code if you do something like:

Future future = InThe.Future(controller.LongRunningTask(GetParameterValue()));

? Does GetParameterValue() get executed immediately, and LongRunningTask get executed "later"? What if I change the value of controller in the next line of code - might it change the invocation if the thread hasn't started yet, or not? What about the thread safety of InThe?

Also bear in mind that futures don't have to have anything to do with multi-threading. I've got some LINQ code I'm working on at the moment which effectively lets you set up a load of data observers, then push some data, then get the values later. For instance:

IDataProducer dp = new DataProducer();

IFuture count = dp.Count();

IFuture maxLength = dp.Max(x => x.Length);

// etc

dp.ProduceAndEnd(someListOfStrings);

int realCount = count.Value;

int realMaxLength = maxLength.Value;

// etc

The code was originally written for a slightly different situation, but I think it's a neat use case - and one which involves futures but explicit timing on a single thread. I wouldn't want each of the aggregates to end up running on a different thread here.

Anyway, time to shut up now.

Jon

Thom
01/02/2008 10:31 PM by
Thom

I made a half-arsed attempt at something a bit more transparent a while back:

http://thom.org.uk/blog/FutureValuesWithCastlesDynamicProxy.aspx

Given Jon's comment above, this is potentially even more aggravating, as consumers would have no indication at all that something odd is happening, but YMMV.

Jeremy Gray
01/02/2008 11:29 PM by
Jeremy Gray

Oren, as much as I admit that I haven't yet had a chance to look at what I'm about to mention, I'm wondering if you have yet had any time to look at the ParallelFX CTP and its Tasks and Futures?

Ayende Rahien
01/03/2008 04:38 AM by
Ayende Rahien

The codethat you listed doesn't work, you need to explicitly state the T of the method.

I find it ugly.

Future future = InThe.Future(() => controller.LongRunningTask());

I am talking specifically about concurrent futures here, so threading is always involved.

GetParameterValue() will be called immediately, changing the value of controller will not affect the future call.

That is not something that I would push to production without some thought, mind you.

I actully did push a a Future to production yesterday, but it was of the first, explicit variety.

James Arendt
01/03/2008 05:18 AM by
James Arendt

Future future = InThe.Future(() => controller.LongRunningTask());

You are incorrect in stating that you have to explicitly declare T for the method. The compiler can in fact correctly determine the type based on the lambda function.

Jon's code was correct. Try it. :-)

Ayende Rahien
01/03/2008 05:41 AM by
Ayende Rahien

James,

Wow, you are correct.

But I tried that, and it didn't work.

Francois Tanguay
01/03/2008 07:15 AM by
Francois Tanguay

Regarding syntax, you could've used:

InThe.Future(controller.LongRunningTask);

Jon Skeet
01/03/2008 09:24 AM by
Jon Skeet

Regarding () => controller.LongRunningTask(), that should be fine.

Perhaps you tried the C# 2 "equivalent":

delegate { return controller.LongRunningTask(); }

? That wouldn't work in C# 2, but would work in C# 3 due to the enhanced type inference.

But the answer from Francois is probably the best one :)

Jon

Tobin Harris
01/03/2008 10:18 AM by
Tobin Harris

It looks cool, but I'm not sure I get it. Why not just mark LongRunningTask as synchronised? Sorry if it's a dumb question!

Ayende Rahien
01/03/2008 11:46 AM by
Ayende Rahien

Not if I wanted to pass parameters

Ayende Rahien
01/03/2008 12:18 PM by
Ayende Rahien

Tobin,

It is executing in another thread, synchronized is another issue

Tobin Harris
01/03/2008 12:25 PM by
Tobin Harris

Thanks Ayende.

It looks like calling clients "block" whilst waiting for the Future to get it's result?

I see that the result is calculated on another thread, but is that critical to this pattern?

A synchronised method would enforce calling threads to queue up so that only one could execute the code at a time.

So, both things appear to achieve the same objective?

(Actually, I know I'm wrong on this, but just want to explain where I don't get it!)

Jon Skeet
01/03/2008 12:36 PM by
Jon Skeet

Tobin,

The point is to get other useful work done on the original thread, while something else happens on the LongRunningTask thread. When the original thread can't do any more useful work until the long running task has completed, it can ask for the value - which will block until it's ready.

James Arendt
01/03/2008 01:10 PM by
James Arendt

Francois's solution to simply pass the name of the method in, unfortunately, does not appear to work in this case.

The lambda appears to be the only approach where type inferencing works.

Jon Skeet
01/03/2008 02:59 PM by
Jon Skeet

Lambda or (ugly) anonymous methods both work, yes. I must admit I'm surprised that the method group version doesn't work though.

I guess it's something deep inside the type inference bit of the spec which treats anonymous functions differently to method groups. That part of the spec is horrendous to read these days - it's all a lot more complicated for C# 3 than it was for C# 2. A lot more powerful, of course, and pretty much necessary for LINQ to work, but nightmarish to reason about.

Just looking at the spec briefly, I would have expected 7.4.2.6 (second bullet) to work in this case. I'll investigate further when I don't have a screaming 19-month-old on my knee...

Jay R. Wren
01/03/2008 03:04 PM by
Jay R. Wren

I just find it very beautiful once I get my head wrapped around it.

Dustin Campbell
01/03/2008 03:19 PM by
Dustin Campbell

Awesome!

However, InThe should be renamed to BackToThe. That way, I can write this:

Future future = BackToThe.Future(controller.LongRunningTask());

And of course, FutureInterceptor should be renamed to FluxCapacitor.

Jeremy Gray
01/03/2008 05:43 PM by
Jeremy Gray

@Jay - Just imagine how beautiful it would be if Future of T implemented an implicit cast to T. :)

Ayende Rahien
01/03/2008 05:49 PM by
Ayende Rahien

Jeremy,

You probably don't want to do that, and anyway you can't (unless they changed the limit on implicit conversion to interfaces.

Andrey Shchekin
01/03/2008 06:04 PM by
Andrey Shchekin

Have you looked at the Parallel FX? I think they have a Future.

Btw, futures and perl6's junctions make me wonder if there is a place in a language for things like that -- the X that transparently behaves as T for all operations on it except several special ones. Like 5 + future int => future int.

Jeremy Gray
01/03/2008 07:06 PM by
Jeremy Gray

@Ayende - I hear ya. I was mostly just dreaming a bit and thinking of what it would be like if one could do that. Mind you, I'm not sure the language/compiler would actually limit you from supporting the implicit conversion in a useful number of cases. I have a LazyLoad of T class, for example, kicking around somewhere that supports conversion to T. Perhaps I'll have to dig it up and see what limits it would bump into.

Jon Skeet
01/03/2008 07:21 PM by
Jon Skeet

I've just been looking into the method group version (i.e. InThe.Future(controller.LongRunningTask).

It should work.

It doesn't due to a bug in the compiler - it doesn't implement the spec correctly with regards to output type inference and method groups.

It's a rather obscure bug, fortunately - unlikely to be a problem very often!

Jon

Ayende Rahien
01/03/2008 07:24 PM by
Ayende Rahien

Jon,

You have no idea how often I hit into this bug

Tobin Harris
01/04/2008 10:14 AM by
Tobin Harris

Jon

Thanks for the explanation, I've got it now :)

Comments have been closed on this topic.