Almost Useful: Java Type Intersection.
Friday, November 23rd, 2007First, for my subscribers that celebrate it, Happy Thanksgiving!
I’ve written about it before, but I think its worth revisiting. Type intersection would be a highly useful feature if not for one thing. “It is not possible to write an intersection type directly as part of a program; no syntax supports this.” - JLS (ยง4.9). That seems like a poor excuse to not support a feature as potentially powerful as type intersection could have been.
They were bold enough to add syntax all over the place for Generics. They added new syntatical meanings for ‘?’ ‘<’, and ‘>’. As a matter of fact, they added a syntax within that construct for handling Type Intersections. Would it really be that difficult to reuse that syntax outside of capture conversions and type inference? Heck, maybe even make it reifiable, although that’s not *as* important.
One example others have used in the past where it would be useful to have this type intersection is with the marker interface RandomAccess. While marker interfaces are less useful now that we have annotations, it none-the-less exists, and can be useful for ensuring that the user of an algorithm passes in a compatible list.
For example, its quite possible to do the following, even with the currently crippled implementation of type intersection.
<T extends List<String> & RandomAccess> void foo(T list) { ... }
You know that you’re getting a random access list. The pain point is that you can not do the following:
<T extends List<String> & RandomAccess> T foo() { return new ArrayList<String>(); }
The reason that isn’t legal is quite simple, even if its not obvious. T is any type that satisfies List<String>&RandomAccess, so you don’t know that it is an ArrayList. You might have MyNonArrayList<String> list = foo(); Oops, that would be an incompatible assignment.
The better approach would be to have the return type be an explicit type that is List<String>&RandomAccess. As a matter of fact, my suggestion is to use that syntax exactly, unless there is a compiler-grammar reason not to. So, our T foo() line becomes:
List<String>&RandomAccess foo() { return new ArrayList<String>(); }
So then we can do: List<String>&RandomAccess list = foo(); Actually, we could just use List<String> list=foo() if we don’t care about RandomAccess.
An important addition to make to this would be casting. For legacy support, if I have a List<String>, but I know that it should be an ArrayList (or some other RandomAccess), I should be able to cast: foo((List<String>&RandomAccess)list);
