java.lang.concurrent.Future<T> is an example of an explicit future, where client code is well aware that the object it is handling is not a direct reference to the value of interest, and must invoke a method to obtain the value (Future.get() in the case of java.lang.concurrent.Future).

That's all very well, but if you have collaborators that expect to deal with the value T you have limited options:

You could invoke get() on your future, wait for it to be realised, then pass the realised value to the collaborators. This defeats the purpose of Future's, since what you really want is to do as much other work as possible before future.get() is called.

Alternatively, you could modify the collaborators to know that they are dealing with a Future. But you don't really want to do that either - its an implementation detail that they should not be concerned with.

What you really want is to pass around implicit futures that hide the fact that the object is anything other than a pojo.

You can create implicit futures by wrapping an explicit future<T> in an implementation of interface T and delegating all of the methods to future.get().xxx(). Here's what that might look like:

// the type expected by client code
interface ExpensiveToCompute {
    public BigDecimal getValue1() throws Exception;
    public BigInteger getValue2() throws Exception;
}

interface Computer {
    public ExpensiveToCompute compute() throws Exception;
}

class SynchronousComputer {
    public ExpensiveToCompute compute() throws Exception {
        // ..
    }
}

// the implicit future, delegating to an explicit future
class ImplicitFutureExpensiveToCompute implements ExpensiveToCompute {
    private Future&lt;ExpensiveToCompute> delegate;

    public ImplicitFutureExpensiveToCompute(
        Future&lt;ExpensiveToCompute> aDelegate) {
        delegate = aDelegate;
    }

    public BigDecimal getValue1() throws Exception {
        delegate.get().getValue1();
    }

    public BigInteger getValue2() throws Exception {
        delegate.get().getValue2();
    }
}

// the async version that returns implicit futures
class AsynchronousComputer implements Computer {
    private ExecutorService executor = ..;
    private SynchronousComputer sync = ..;

    public ExpensiveToCompute compute() throws Exception {
        return new ImplicitFutureExpensiveToCompute(
            executor.submit(new Callable&lt;ExpensiveToCompute>() {
                public ExpensiveToCompute call() {
                    return sync.compute();
                }
            }));
    }
}

Pretty straight-forward, although there's quite a bit of boiler-plate, and i've passed the buck on exception handling.

This example is very simple, but things can get more involved if, for example, you want to use Future's overloaded get(long timeout, TimeUnit units) and handle timeouts appropriately (say, by returning a default value).

What if, instead of all this, you could pass your current synchronous implementation through some machinery that converted appropriately annotated methods to run asynchronously and return implicit futures, without the chore of having to create those classes yourself?

It might look like this:

// the type expected by client code
interface ExpensiveToCompute {
    public BigDecimal getValue1() throws Exception;
    public BigInteger getValue2() throws Exception;
}

interface Computer {
    @ComputationallyExpensive
    public ExpensiveToCompute compute() throws Exception;
}


// the synchronous implementation - exact same as before
class SynchronousComputer implements Computer{
    public ExpensiveToCompute compute() throws Exception {
        // ..
    }
}

// the async version, returning implicit futures
class AsynchronousComputer implements Computer {
    private Computer async;

    public AsynchronousComputer(
        AsyncificationService anAsyncifier, Computer aDelegate) {
        async = anAsyncifier.makeAsync(aDelegate);
    }

    public ExpensiveToCompute doSomething() {
        return async.doSomething();
    }
}

This time we didn't need to create the implicit future implementation, cutting a whole lot of boiler-plate, and the async implementation got a fair bit simpler too. We marked the expensive method with an annotation so that the AsyncificationService knew to work its magic on that method.

There's a lot more useful stuff we can do when we have the machinery for converting synchronous methods to asynchronous methods that return implicit futures. For example we can transparently handle exceptions and return default values, or we can impose timeouts and return default values if we don't get a result in time, etc., etc.

If you want to see how we might implement such machinery, or want to try using it, fork the code for Implicit-Futures from github.

blog comments powered by Disqus