Wednesday, February 23, 2011

A harder puzzle

Suppose I have a procedure that needs to make temporary use of some expensive resource. The usual way to code this up is something like this:
(defun foo (x)
  (let ((resource nil))   ; or #f or whatever
    (unwind-protect
        (progn (setq resource (obtain-resource pool))
               (compute x resource))
      (if (not (null resource))
          (return-resource pool resource)))))
There are two problems with this. The first is a minor race condition where the resource can be lost if an asynchronous interrupt is taken right after obtain-resource returns but just before the value is assigned to the variable. We'll ignore that problem for now. The bigger problem is that we cannot easily spot the separation between the parts of foo concerned with resource management and the parts needed for computing the return value.

What we want to do is abstract out the resource management:
(defun foo (x)
  (call-with-resource resource-pool
    (lambda (resource)
      (compute x resource))))

(defun call-with-resource (pool receiver)
  (let ((resource nil))
    (unwind-protect
        (progn (setq resource (obtain-resource pool))
               (funcall receiver resource))
      (if (not (null resource))
          (return-resource pool resource))))) 

(One could use macros here, too.)

Now we can see that foo just supplies an additional argument to a call to compute. As an additional bonus, we have a simple idiom that correctly encapsulates the acquisition and release of our resource. Other code that has the ‘boilerplate’ needed to manage the resource can be simplified to use our wrapper. It is less likely that resources are dropped by accidentally copying the boilerplate incorrectly. This sort of wrapper code is frequently found in Lisp or Scheme.

The puzzle is “How do you do this in Java?” To be more specific, suppose I have this code:
class Foo {
    ...
    public Answer method1 (int x) throws BadRequest {
        Resource resource = null;
        try {
            resource = pool.obtainResource();
            return computeAnswer (x, resource);
        } finally {
            if (resource != null)
                pool.returnResource(resource);
        }
    }

    private Answer computeAnswer (int x, Resource r) throws BadRequest {
        ....
    }
}

class Bar {
   ...
   public void method2 (Boolean flag, String name) throws NoSuchEntry {
        ExpensiveObject resource = null;
        try {
            resource = expensiveObjectPool.obtainResource();
            if (flag)
               resource.addName(name);
            doSomething(resource); 
        } finally {
            if (resource != null)
                expensiveObjectPool.returnResource(resource);
        }
    }

    private void doSomething (ExpensiveObject expo) throws NoSuchEntry {
        ....
    }      
}
and I want to write something more like this:
class Foo {
    ...
    public Answer method1 (int x) throws BadRequest {
        // WRAPPER CODE HERE
        return computeAnswer(x, resource);
        // POSSIBLE WRAPPER EPILOGUE
    }
 
    private Answer computeAnswer (int x, Resource r) throws BadRequest {
        ....
    }
}

class Bar {
   ...
   public void method2 (Boolean flag, String name) throws NoSuchEntry {
        // WRAPPER CODE HERE;
            if (flag)
               resource.addName(name);
            doSomething(resource); 
        // POSSIBLE WRAPPER EPILOGUE HERE
    }

    private void doSomething (ExpensiveObject expo) throws NoSuchEntry {
        ....
    }      
}
Where the wrapper and possible epilogue (if needed) are some relatively simple, easy to use constructs like a method call or inner class declaration or whatever.

4 comments:

  1. Doesn't the callWithResource way still work? It's just clunkier:

    return pool.callWithResource(new Function<Resource, Answer>() {
        Answer call(Resource r) { return computeAnswer(x, r); }
      });

    ...with the obvious definitions of callWithResource and Function, and — oh, wait, that's a checked exception, isn't it. So we have to wrap it. Ouch:

    public Answer method1 (int x) throws BadRequest {
      try {
        return pool.callWithResource(new Function<Resource, Answer>() {
            Answer call(Resource r) {
              try { return computeAnswer(x, r); }
              catch (BadRequest e) { throw new RuntimeException(e); }
            }
          });
      } catch (RuntimeException e) {
        if (e.getCause() instanceof BadRequest)
          throw e.getCause();
        else
          throw e;
      }
    }

    ...except that this could possibly mistakenly unwrap an exception someone else wrapped, so theoretically it should use a private wrapper class...

    ReplyDelete
  2. So let's assume something analogous for method2. That's the easy part. Now abstract it (e.g. with generics).

    ReplyDelete
  3. I'm surprised this works:

    interface FunctionThrowing<Arg, Res, Exn extends Throwable> {
      Res call(Arg a) throws Exn;
    }

    So, if you duplicate callWithResource (and other high-order functions) with exception-throwing variations, you can make this work, at least until someone wants to throw two exceptions:

    return pool.callWithResource(new FunctionThrowing<Resource, Answer, BadRequest>() {
        public Answer call(Resource r) throws BadRequest { return computeAnswer(x, r); }
      });

    This maybe isn't an improvement. (And I'm starting to sympathize with the people who advocate using only RuntimeExceptions.)

    ReplyDelete
  4. Fortunately defining callWithResource is no more painful than calling it:

    <Result, Exn extends Throwable> Result callWithResource(FunctionThrowing<Resource, Result, Exn> f) throws Exn {
      Resource r = null;
      try {
        r = obtainResource();
        return f.call(r);
      } finally {
        if (r != null)
          returnResource(r);
      }
    }

    ReplyDelete