Brian's Waste of Time

Tue, 28 Dec 2004

As seen on LtU...

Ruby is the new Python
Python is the new Java.
Java is the new COBOL.

1 writebacks [/src/ruby] permanent link

Futures, Part 1.5

Binkley had a reader point out that JDK 1.5 has futures: JDK 1.5 Future

0 writebacks [/src] permanent link

Futures and Concurrent Programming (Part 1)

While reading about Alice (which is a royal pita to build on OS X, btw), I ran into a wonderful explanation of futures. Coupled with having been talking about message driven designs for web applications with a coworker, then later that night finding Gregor Hohpe's event driven architecture talk which uses the futures concept, and, prior to that having been annoyed at the lack of lazy evaluation being available in java (it can be faked via "Java Closures(tm)" though)....

Futures are really nice conceptually, and provide for much more natural and easy to use concurrent design than Java style threading and monitors. It relates to a lot of functional programming concepts, but the key idea is that a future represents an evaluation which has not yet occured. Maybe it is being lazily evaluated, maybe it is being evaluated concurrently in another thread.

A future can be represented very simply:

package org.skife.futures;

public interface Future {
    
    /**
     * Is the result available right now?
     */
    public boolean isAvailable();
    
    /**
     * Obtain the value of this Future, blocking if it is
     * not available.
     * @throws any exception thrown while evaluating the Future
     */    
    public Object getResult() throws Exception;
}

and some kind of evaluator:

package org.skife.futures;

public interface Evaluator {
    Future promise(Expression exp);
}

Which promises to provide the result of the expression at some future time. I tossed together two basic implementations, an AsyncEvaluator (using a util.concurrent pooled executor to handle evaluations) and LazyEvaluator. Both of these are pretty straightforward, and usage looks like:

public void testAsync() throws Exception
{
    final boolean[] finish = { false };
    final Future f = async.promise(new Expression() {

        public Object evaluate() throws Exception
        {
            while (!finish[0]) Thread.sleep(100);
            return "done";
        }
    });

    assertFalse(f.isAvailable());
    finish[0] = true;
    assertEquals("done", f.getResult());
}

public void testLazy() throws Exception
{
    final boolean evaluated[] = { false };
    final Future f = lazy.promise(new Expression() {
        public Object evaluate() throws Exception
        {
            evaluated[0] = true;
            return "done";
        }
    });
    assertFalse(evaluated[0]);
    assertEquals("done", f.getResult());
    assertTrue(evaluated[0]);
}

This works, and solves a number of problems, but is a bit awkward compared to, say, how you make an expression asynchronously evaluated in Alice:

Vector.tabulate (30, fn i => spawn f i)

Which spawns a thread to evaluate f i transparently and makes it available. You can do this using AOP techniques in Java, but it is a touch hairier as you can only really proxy an interface, not a function (python decorators come to mind as being a nice solution), or as is more common in lazily evaluatuated languages.

Of course, this type of stuff plays havoc with state (re all the "State is Evil" blogging that crops up again and again) as if your lazily or asynchronously evaluated future modifies any state, or depends on modifiable state, skeebaz! More on this in part 2 of this entry when I have a chance =)

Oh yeah, the earliest discussions of futures I have found came out of... come on, guess? Yep, Lisp. Argh. (No, I am not a smug Lisp weenie (yet?), but common lisp is looking promising for 2005 as scheme was a lot of fun in 2004). Maybe I'll skip it and go play with Alice some more though =)

7 writebacks [/src] permanent link