It Is Generic After All
Bruce Eckel, March 10, 2004: Generics Aren't
Bruce Eckel, October 8, 2004: ... Using adapters like this would seem to compensate for the lack of latent typing, and thus allow you to write genuinely generic code.
From it's announcement in June 1998, to the final induction into Java 5.0 in August 2004, Java generics has gone through over six years of maturation.
Originally hailed as an efficient and backward compatible extension to the JDK rooted in some esoteric theory, Java generics, especially its erasure based implementation has been under much criticism lately (including on this blog).
One of the complaints leveled against Java generics is that it is not generic:
public class CallF {
public <T> void callF(T t) {
t.f(); // can't call f() here
}
}
In his latest weblog, Bruce Eckel offers several ways around the problem by using adapters. One of them, termed surprising by Bruce, uses an abstract generic adapter instantiated and anonymously extended at the call site.
Here's a distilled version of the example:
[weiqi@gao] $ cat A.java
public class A {
public void f() {
System.out.println("A.f()");
}
}
[weiqi@gao] $ cat CallF.java
public class CallF {
public <T> void callF(HasF<T> adapter) {
adapter.f();
}
}
[weiqi@gao] $ cat HasF.java
public abstract class HasF<T> {
protected T t;
public HasF(T t) {
this.t = t;
}
public abstract void f();
}
[weiqi@gao] $ cat Main.java
public class Main {
public static void main(String[] args) {
A a = new A();
CallF f = new CallF();
f.callF(new HasF<A>(a) {
public void f() {
t.f(); // OK to call f() since t is of type A here
}
});
}
}
[weiqi@gao] $ javac *.java
[weiqi@gao] $ java Main
A.f()
Once understood, the code is quite clear.
The classes CallF and HasF is the library that just want to call a method named f(). No extra requirement is placed on T except that it has the f() method. This qualifies them as true generic algorithm classes.
The class A is a POJO that has an f() method.
In Main we manage to hook up the "library" and the POJO and have the "library", which knows nothing about the POJO, call a method on the POJO, which knows nothing about the "library", just like in C++. Great!
Looking back at the solution, I can't help but notice all the clutter. Suddenly the irony is apparent: We went all the way to add generics into Java, ostensibly to simplify our Java code, yet at the end our code is even more cluttered.
Could we have done the same thing without generics? Of course. This is the land of erasure. Decompiling the classes with JODE, I get:
[weiqi@gao] $ jode -d jode A CallF HasF Main
Jode (c) 1998-2001 Jochen Hoenicke <jochen@gnu.org>
A
CallF
HasF
Main
Decompiled 4 classes.
[weiqi@gao] $ cd jode/
[weiqi@gao] $ cat A.java CallF.java HasF.java Main.java
public class A
{
public void f() {
System.out.println("A.f()");
}
}
public class CallF
{
public void callF(HasF hasf) {
hasf.f();
}
}
public abstract class HasF
{
protected Object t;
public HasF(Object object) {
t = object;
}
public abstract void f();
}
public class Main
{
public static void main(String[] strings) {
A a = new A();
CallF callf = new CallF();
callf.callF(new HasF(a) {
public void f() {
((A) t).f();
}
});
}
}
[weiqi@gao] $ javac *.java
[weiqi@gao] $ java Main
A.f()
Comparing this with the generic classes, we discover that all of our generics mumbo-jumbo bought us exactly one puny little cast!.
Oh wait a minute, have I just written a genuinely generic algorithm in pre 5.0 Java without using generics?
Interesting!
Re: It Is Generic After All
Generics are worse, though, largely due to the XML bracket syntax. This is unfortunate because it collides with so much web stuff. You cannot simply paste generic code fragments into web pages...you now have to worry about escaping all of those XML brackets. You really run into problems when syndicating brackets in places like this comment box. I don't know what the rules are, so I'll avoid the brackets altogether.
Re: It Is Generic After All
Anyone who's on a quest for "We can do this in C++ with templates, so let's see if we can do it in Java now that generics is here" will be disappointed to discover that C++ templates and Java generics are quiet different.
I think what we need to do is to use Java generics where it makes sense. We also need to be familiar with the specs and on the look out for innovative uses of generics.
Eventually, we will discover a set of things that Java generics can do that C++ tempalets cannot.