Implementing futures in C#

by Porges

Why?

I was bored, and it didn’t seem to have been done before, so here’s some Future action in C#.

The Code

using System;
using System.IO;
using System.Reflection;
using System.Threading;
 
public class Future<T> {
        public delegate R FutureDelegate<R>();
        public Future (FutureDelegate<T> del) {
                Del = del;
                Result = del.BeginInvoke(null,null);
        }
        private FutureDelegate<T> Del;
        private IAsyncResult Result;
        private T PValue;
        private bool HasValue = false;
        private T Value {
                get {
                        if (!HasValue) {
                                if (!Result.IsCompleted)
                                        Result.AsyncWaitHandle.WaitOne();
                                PValue = Del.EndInvoke(Result);
                                HasValue = true;
                        }
                        return PValue;
                }
        }
        public static implicit operator T(Future<T> f) {
                return f.Value;
        }
}
 
public static class MainClass {
        //This is purposely wasteful!
        public static ulong Fib(ulong n) {
                if (n > 1) {
                        return Fib(n-1)+Fib(n-2);
                }
                else if (n == 1)
                        return 1;
                else //n == 0
                        return 0;
        }
        //Demo using futures.
        public static void Main(string[] args) {
                Console.WriteLine("First, call synchronously.");
                Console.WriteLine(Fib(40));
                Thread.Sleep(1000);
                Console.WriteLine("Next, call asynchronously.");
                Future<ulong> fib40 = new Future<ulong>(delegate{
                        return Fib(40);
                }); //Begins computing Fib(40) at this point...
                Thread.Sleep(1500);
                Console.WriteLine("Note that we can do other things in the mean time, and that the thread only blocks when we ask for the value.");
                Console.WriteLine(fib40); //Need it now!
                Thread.Sleep(2000);
                Console.WriteLine("We can then ask for the computed value as many times as we like.");
                Console.WriteLine(fib40); //Already computed.
        }
}

Caveats

Most notably, this doesn’t do promise pipelining (and I doubt I could without some compiler magicking), so instead of nesting futures, you’ll want to seperate them out. That is; instead of:

t3 = new Future(delegate{return new Future(delegate{return x.a()}).c(new Future(delegate{return y.b()}))});

…you’ll want to do:

t1 = new Future(delegate{return x.a()});
t2 = new Future(delegate{return y.b()});
t3 = new Future(delegate{return t1.c(t2)});

…although you’d probably want to do this anyway if you don’t want to wander into The LispZone.