Since they were released simultaneously, I consider them to be tightly coupled. For instance, here are simplified versions of an interface and implementation I recently wrote:
Note: I am having difficulty representing greater-than and less-than symbols in Blogger's editor, so you'll have to do with { and }.
Version 1: Java 5, Generics, Covariant return types
public interface Model{T extends Model{T}} {
T read(InputStream in);
T write(OutputStream out);
}
public class MyModel implements Model{MyModel}Thanks to the covariance, I can write a method chain like this:{
public MyModel read(InputStream in) {
...
}
public MyModel write(OutputStream out) {
...
}
public MyModel setName(String name) {
...
return this;
}
public String getName() { ... }
}
new MyModel()
.read(in)
.setName("foo")
.setStopAtMain(false)
...
.write(out);
With Java 1.4, the code would have to look like this
Version 2: Java 1.4
public interface Model {And the method chain would result in a syntax error:
Model read(InputStream in);
Model write(OutputStream out);
}
class MyModel implements Model {
public Model read(InputStream in) { ... }
public Model write(OutputStream out) { ... }
...
}
public static void foo() {Which you could hack around with an ugly cast:
new MyModel()
.read(in)
.setName("foo")
^ The method setName(String) is undefined
for the type Model.
.write(out);
}
public static void foo() {Back to the Java 5 example: My point is just this: covariant return types don't require generics. All that messy code in version 1 could look much simpler because covariant return types exist on their own without generics:
((MyModel) new MyModel()
.read(in))
.setName("foo")
.write(out);
}
Version 3: Java 5, Covariant return types
public interface Model{{T extends Model{T}}
TModel read(InputStream in);
TModel write(OutputStream out);
}
public class MyModel implements ModelLesson learned: I know generics fairly well, but there's a difference between knowing when it's useful and when it isn't. Said another way: when you have a Generic hammer everything looks like a generic nail.{{MyModel}
public MyModel read(InputStream in) {
...
}
public MyModel write(OutputStream out) {
...
}
public MyModel setName(String name) {
...
return this;
}
public String getName() { ... }
}
Thanks to David Plass for pointing this out.

