Pages

Monday, December 04, 2006

Super Type Tokens

Class<T> works fine so long as T is a raw type, but I recently needed to pass around references to full blown generic types. For example, due to the fact that Java uses erasure to maximize compatibility, List.class compiles but List<Integer>.class does not.

Ted recently ran into this problem, too. He was lucky enough to get off with a warning, but my code actually needs to differentiate between List<Integer> and List<String>.

Neal came to the rescue with a clever (and cleverly named) pattern for retaining otherwise non-reifiable types at runtime. Check out super type tokens.

In a nutshell, instead of saying List<Integer>.class, you can say new TypeReference<List<Integer>>() {}, where the API for TypeReference may look very similar to that of Class.

4 comments:

  1. Yea, that Gafter's Gadget is definitely a brilliant idea! By the way, what for you are developing the dependency injection framework?

    ReplyDelete
  2. Anonymous8:26 PM

    Seems like a lot of reflection for little gain, why don't you do this instead:

    interface Factory< T > { T newInstance(); }
    ...
    Factory< List< String > > stringsFactory = new Factory< List< String > > {
    public List< String > newInstance() { return new List< String >(); }
    }

    And on the naming front, what's wrong with Factory.

    ReplyDelete
  3. Eugene, just toying with some ideas. ;)

    Anonymous, the newInstance() method was just a small example. Super type tokens go well beyond creating new instances of types.

    The syntax may leave a little to be desired, but you can always add sugar. The semantics are what's important.

    ReplyDelete
  4. Anonymous11:49 AM

    You should just use Haskell (which is where Java generics came from in the first place), in which case you'd have different types for [Integer] (the equivalent of List<Integer>) and [String] (the equivalent of List<String>).

    ReplyDelete