<< Ripe Allocations, revisited | Home | Pop quizz Java: final vs. NPE, 0:1 >>

The Futures of Java

Subtyping considered useful

So here I was playing with the type checker for our industrial-strength toy language ABS. This works, of course:

  interface A;
  interface B extends A;
  interface I {
     A doA();
     B doB();
  }

  Unit doIt() {
     I i = … ;
     /* All green, covariant return type: */
     A a = i.doB();
  }

A similar thing works of course also in Java. But, now back to the Futures! In ABS, we have futures, and of course it should be straight forward to turn the synchronous call into an asynchronous one:

   /* Works: */
  Fut<B> b = i!doB();
  A a = b.get; /* covariance for method "calls" (get is a special built-in) */

  /* Didn't - no covariance for parametric data types! */
  Fut<A> b = i!doB();

So I can do A a = i.doB() but not Fut<A> fa = i!doB(); A a = fa.get -- disappointing and not orthogonal at all!

While subtyping of parametric datatypes (in the functional subset of ABS!) can be easily told to make use of subtyping, it doesn't work that way in OO languages: the required subtyping rule would allow you to write values of the wrong type -- here's Jon Skeet explaining it why a list of animals is not the same as a list of cats or a list of dogs, and the hilarity that ensues when you mix them up.

As usual, functional programming saves the day.

Full Java code illustrating the problem for your delectation:

import java.util.concurrent.*;

interface A {}
interface B extends A{}

public class FuTest {

  ExecutorService es;
  Callable<B> task;
	
  void doIt() throws InterruptedException, ExecutionException {
	Future<A> futA = null;
	Future<B> futB = null;
	/* Does not type check: */
//	futA = es.submit(task);		
	futB = es.submit(task);
	A a = futB.get();
	a = futA.get();
  }
}



Add a comment Send a TrackBack