ArticleS. UncleBob.
BoundedWildcards [add child]

Bounded Wildcards: Java Generics

Imagine that you have a class that looks like this:

class Handler {
private List list;

public Handler(List list) {
this.list = list;
}

public void add(Object o) {
list.add(o);
}

public void handle() {
for (int i = 0; i < list.size(); i++) {
Shape s = (Shape) list.get(i);
/*..*/
}
}
}

This is about as un-type-safe as you can get. You can call add with any type at all. And yet, if you look at the handle method it's easy to see that we are really expecting to be dealing with Shape instances. Of course we can fix this by adding a little bit of type safety to the add method as follows:

public void add(Shape s) {
list.add(s);
}

However, since the list is passed as an argument into the constructor, it might have been loaded with things that weren't Shapes prior to construction. What we really want is a way to insist that the list contain shapes, and nothing but shapes. We can do this by adding generics as follows:

class Handler {
private List<Shape> list;

public Handler(List<Shape> list) {
this.list = list;
}

public void add(Shape s) {
list.add(s);
}

public void handle() {
for (Shape s : list) {
/*..*/
}
}
}

Now Handler can only take lists of Shapes. (Note the new iteration syntax too.)

This works OK until someone wants to pass a list of Squares into the handler as in the following:

public void handleSquares() {
List<Square> ls = new ArrayList<Square>();
/* get a bunch of squares */
Handler h = new Handler(ls); // <---Error
h.handle();
}

The compiler complains that you cannot pass a List<Square> to an argument that expects a List<Shape>. Remember from my previous blog that lists of derivatives are not derivatives of lists of bases. That previous blog also told us how to solve this by using the <? extends Shape> syntax, as shown below:

class Handler {
private List<? extends Shape> list; //......... <--- Modified

public Handler(List<? extends Shape> list) { // <--- Modified
this.list = list;
}

public void add(Shape s) {
list.add(s); //.............................. <--- Error!!
}

public void handle() {
for (Shape s : list) {
/*..*/
}
}
}

This resolves the previous error, but at the expense of a new one. The call to add won't compile because you can't add a known type into a list that holds an unknown type. Somehow, when we are adding, we have to be dealing with a known type. We can do that by using the <? super Shape> syntax as follows:

class Handler {
private List<? super Shape> list; //............ <--- Modified

public Handler(List<? extends Shape> list) {
this.list = list;
}

public void add(Shape s) {
list.add(s);
}

public void handle() {
for (int i = 0; i < list.size(); i++) { //.....<--- Modified
Shape shape = (Shape) list.get(i);
/*...*/
}
}
}

You may not have seen this syntax before. It's a little difficult to understand at first. A List<? super Shape> is a list into which you may add Shapes. Another way to think of this is that the type <? super T> is an unknown type that T can substitute for. You may have to read that several times before you understand it. I certainly did. So here's yet another way to think about it. The type <? super T> is a type that T is derived from. It is a base class of T. Clearly if D is derived from B then you can put D instances into a List<B>. Likewise, since T derives from <? super T>, you can put T instances into a List<? super T>. Follow? No? Neither did I for awhile. It takes a bit of getting used to.

One more thing to get used to is the assignment this.list = list. Can you reliably assign a List<? extends T> to a List<? super T>? The compiler says you can. It also makes a certain amount of sense. After all if I have a list of things derived from Shape (e.g. List<? extends Shape>) then that is substitutable for a list of some base type that Shape derives from (e.g. List<? super Shape>). In other words List<? super Shape> is more generic than List<? extends Shape>. In some very strange sense List<? extends Shape> is a subtype of List<? super Shape>.

One last factoid: A List<Shape> can be passed to both List<? extends Shape> and List<? super Shape>.

Unfortunately, by weakining the type of the list instance variable; we had to put the cast back into the handle method. That's a shame. But there are worse problems.

Our original intent was to pass in a List<Square> to the Handler. We've done this, and it works. But now there is nothing to stop us from adding a Circle instance to the Handler.

public void handleSquares() {
List<Square> ls = new ArrayList<Square>();
/* get a bunch of squares */
Handler h = new Handler(ls);
h.add(new Circle());// .............<--- THIS IS TERRIBLE!!!!!
h.handle();
}

This is no good. We need a way to make sure that if we pass a List<Square> to the handler, then nothing but Squares can be added to the Handler. Luckily the new language features allow us to create generics of our own. This is really simple to do.

class Handler<T> { //.....................<-- A new generic.
private List<? super T> list;

public Handler(List<? extends T> list) {
this.list = list;
}

public void add(T t) {
list.add(t);
}

public void handle() {
for (int i = 0; i < list.size(); i++) {
Shape s = (Shape) list.get(i);
/*...*/
}
}
}

This class can be used as follows:

public void handleSquares() {
List<Square> ls = new ArrayList<Square>();
/* get a bunch of squares */
Handler<Square> h = new Handler<Square>(ls); //....<<--- Cool!
h.handle();
}

This compiles, and solves the problem. We can not add Circle instances to a Handler<Square>. But there is a significant problem. The handle method expects Shape instances. But nothing else enforces that. For example, there is nothing to stop us from creating a Handler<Dog>, where Dog does not derive from Shape.

We can resolve this by constraining the type argument of Handler to be a derivative of Shape as follows:

class Handler<T extends Shape> {

This prevents Handler<Dog> from being created. Whatever T is, it must derive from Shape.

Now let's get rid of that ugly loop. I want to be able to use the new typesafe looping syntax. Consider the following:

class Handler<T extends Shape> {
private List<? super T> inlist;
private List<? extends Shape> outlist; //...<--- Two list references.

public Handler(List<? extends T> list) {
inlist = outlist = list; //................<--- Both list variables refer to the same list.
}

public void add(T t) {
inlist.add(t);
}

public void handle() {
for (Shape s : outlist) { //...............<--- Just what we wanted.
/*...*/
}
}
}

This solution is ironic. C++ templates did not have bounded wildcards. There was no way to pass a List<Square> to a List<Shape>. One common technique in C++ was to create one list for each derivative. So we'd have a List<Square> and a List<Circle> and keep all the subtypes seperate. Using Bounded Wildcards in Java we can keep the objects in the same list; but we may want to have two different list variables, one for adding, and one for getting. Both variables refer to the same list. Isn't that wierd?




 Wed, 9 Nov 2005 07:11:54, nraynaud, learning
I'm not sure this generics stuff is a good thing. I spend my time answering questions about design, I see everyday code that make me think that maybe we should reconsider the ban of the death sentence (in France). Is the public ready for such thing as separation between collection reader and collection writer (the difference between extends and super) ? It can't understand that "no, business object don't have the right to import SQL packages" (actually, the project I work on is worst than that) and "yes, trivial Stored Procedures are useless".

Moreover, java's generics implies some inference stuff, wich is very tricky to explain and debug.
 Wed, 9 Nov 2005 08:57:06, ,
Crikey. Every time I read about Java 5 I find the simplicity and elegance of Smalltalk more appealing.
 Wed, 9 Nov 2005 09:00:34, Uncle Bob., Is the public ready?
I sympathize with the view that Java generics have gone a bit overboard. I'm not sure that the bounded wildcard syntax is really worth all the fidgeting it implies. However, I also think that companies should not hire programmers who are incapable of understanding basic design principles. There are far too many programmers out there who have no sense of design. These folks subtract more than they add.
 Wed, 9 Nov 2005 10:18:49, zorkerman, nice
I have to say I have not jumped onto the java 5 board, because my expectations of c templates makes this stuff all hurt my head. Keep up the articles though. This is the first time I think I could make a class that plays the template game like I would want it to work.

Though I must say, the more I read the more backwards compatibility seems to be a deal with the devil that the java community is going to regret.

anyway nice!
 Wed, 9 Nov 2005 10:35:13, nraynaud, Is the public ready?
Bob > I've always tried to educate them, because I'm not in position to "eliminate" them. Moreover, I've never found a company where I could put in practice XP freely and confirm my learning by practicing.

You're exactly at the opposite position (you have the power, and you understand all this), so I understand why you think like this.

But I don't think I'll find a market if I try to create my consulting company in France.
 Wed, 9 Nov 2005 14:34:01, Bill Caputo, Are generics a good thing?
nraynaud, I think this is a good addition to Java - but then I am looking at it from the POV of what *I* want to do with *my* tools (i.e. not what I want others to do with *their* tools). IOW, "good" is based on one's perspective (I may have said this somewhere else recently...). Having found myself holding both the enabling and directing perspectives at various times (and having consulted for people holding both perspectives), my philosophical solution is much like Bob's (surround yourself with people who know how to use their tools, so you can focus on empowering them instead of constraining them), and I recently made it my pragmatic solution too (i.e. I recently seized an opportunity to work like this).

But, my recommended strategy for when this is not possible (based on similar experiences with C++ teams): Use generics to define lower-level classes, focus your best people on the tasks that create those classes, build the rest of your system using these basic building blocks - i.e. Encourage thinking in types and abstractions rather than objects and classes (yes this is a good thing anyway, this is simply a concrete example of one reason why).

Developing good types (removing Primitive Obsession is a good start), and raises the level of discourse (in code) up a level. This tends to concentrate the use of generics in the lower levels of the code, leaving just the use of generic types for the others to learn.

I.e.: code like Bob is describe would be more common in your basic type definitions while your "business logic" (ugh I hate that term) would only consume these types. This lowers the learning curve a bit (and makes for better design) since declaring variables of a generic type is easier to grok than defining classes with generic signatures (or generic types).

Thus, your more knowledgable programmers can take the tasks (or the projects depending on your organization) that drive out the basic types, leaving your cannon fodder to handle tasks that consume them.

Like I said, I don't like working like this, I think its less effective (and more expensive) than hiring a smaller number of people who can actually do (or learn!) the job of programming (imagine the absurdity of hiring self-described master carpenters who only know one or two of the tools in their tool boxes!!), but as you alluded to, sometimes these things are out of our control; this is how I try to make the best of it.
 Wed, 9 Nov 2005 18:16:04, Jim Menard, What a turnoff
I'm with unnamed above. Give me dynamically typed languages. If this is where Java is going, I don't want to follow.

A personal rant: http://www.io.com/~jimm/blog/index.php?entry=/computers/programming/java_generics.txt
 Wed, 9 Nov 2005 23:08:17, Uncle Bob, If this is where java is going...
Jim, I completely sympathize. Nice blog BTW. Still, I think we'll all have to follow for awhile longer yet. Java and C# still have a few years of domination yet to go. But the time is coming when dynamic typing will supercede static typing IMHO.

Have you looked at the spec for C# 3.0? Untyped objects, lamda expressions, uniform query language. Just a hint of dynamic typing. Java will have to follow suit (unless it gets there first).
 Thu, 10 Nov 2005 06:04:31, nraynaud, static/dynamic typing debate
I'm definitely for static : I've not spend so much time, understanding type theory, hierarchy, late binding, generics, inference, o'caml weak types, functors, clean's eagerness etc. instead of sleeping to throw everything it to the bin. :)

(ok, I've more serious arguments but we all know them here)
 Thu, 10 Nov 2005 07:40:20, ,
nraynaud: are there any type systems that actually help OO programmers do the most error-prone part of their job, which is implement interfaces correctly? No statically typed language that I've seen, including OCaml, helps here. All static type systems I've seen ensure that types are used correctly but that's the easy part. The vast majority of my bugs are caused by me implementing types incorrectly, and static type systems offer me NO HELP WHATSOEVER.

So, static type experts, pull your fingers out and address the problems OO language users really have.
 Thu, 10 Nov 2005 21:43:23, Jim Menard, Follow, or be pulled along?
Uncle Bob, you wrote, "Still, I think we'll all have to follow for awhile longer yet." Frankly, I don't see a high rate of Java 1.5 adoption. It feels more like Sun is pushing Java 1.5, instead of the developers and corporations asking for it and wanting it.

I looked at C# once a while ago, but have not kept up with it. I don't program on Windows, so I haven't kept up with it. I know it can be used elsewhere, but for cross-platform development I use Java or Ruby. I'll give the latest C# a look, because I can always learn something from any language.
 Fri, 11 Nov 2005 11:34:23, ,
C# 1 was about as good as Java: some things were better but other things were worse. But C# 2 is far better than Java 5 thanks to Java's generics and autoboxing both being more complex and less powerful than the same features in C#.
 Wed, 16 Nov 2005 13:10:49, Ben Monro, totally unrelated

 Wed, 16 Nov 2005 15:45:42, Sam Mesh, Times are getting better! :)
Though programming languages have evolved a lot they are still silly exercises trying to express design/compile time logic/constraints. But it was worse in before-template OO - you can have 100% compile time valid code that is 100% runtime wrong:

Object x[] = new String[3];
x[0] = new Integer(0);

Are times getting better? :)
 Fri, 18 Nov 2005 04:25:08, ,
That hole in the type system still exists in Java 5, and the new generics mechanism opens up *new* holes!

For example, doSomething() can be written so that the following two statements compile in Java 1.5 but the second statement makes doSomething fail at run time. How many different ways can you write doSomething to make this happen in Java 1.5?

int anInt = doSomething();
long aLong = doSomething();

 Mon, 12 Dec 2005 13:17:42, lkraft, Won't compile
Nice article, but the final two Handler definitions don't compile. )Oddly, IntelliJ doesn't flag the syntax errors until a build is executed.)
 Mon, 12 Dec 2005 16:58:45, lkraft, this compiles, though
public class Handler<T extends Shape> {
private List<? super T> m_inlist;
private List<? extends T> m_outlist; //...<- Two list references.

public Handler(List<? extends T> p_list) {
List list = p_list;
m_inlist = p_list;
m_outlist = p_list; //................<
- Both list variables refer to the same list.
}

public void add(T p_t) {
m_inlist.add(p_t);
}

public void handle() {
for (Shape s : m_outlist) { //...............<--- Just what we wanted.
/** **/
}
}
}
 Mon, 12 Dec 2005 16:59:53, lkraft, whoops, here's the one that compiled
Take a look at the code in the constructor.

public class Handler<T extends Shape> {
private List<? super T> m_inlist;
private List<? extends T> m_outlist; //...<- Two list references.

public Handler(List<? extends T> p_list) {
List list = p_list;
m_inlist = list;
m_outlist = list; //................<
- Both list variables refer to the same list.
}

public void add(T p_t) {
m_inlist.add(p_t);
}

public void handle() {
for (Shape s : m_outlist) { //...............<--- Just what we wanted.
/** **/
}
}
}
 Tue, 13 Dec 2005 12:18:23, Vishal Shah, Were you doing TDD?
UB - I know you were driving the changes by unit-tests. It would have been nice if you had posted them as well, so I could simply copy them, along with the Handler code, and try some variations of my own. Alltogether, fascinating read. But, I must say Sun's compiler writers must have worked really hard, to work with generics and get them right in each of the frindge cases. I know, Sun was planning on adding generics since 1999. See the original GJ spec web page [http://homepages.inf.ed.ac.uk/wadler/gj/index.html#may99]

Thanks UB.
-Vishal Shah (A rant about this on <a href="http://goldenv.blogspot.com/">my blog</a>)
 Sun, 18 Dec 2005 15:50:08, ,
since you seem to just want a handler that takes only one class type and allows that (not subtypes or multiple types in a single handler instance), can't you just write

class Handler<T> {
private List<T> list;

public Handler(List<T> list) {
this.list = list;
}

public void add(T t) {
list.add(t);
}

public void handle() {
for (T t : outlist) {
/*...*/
}
}
}

ok you were just using it as an example of what the expressions are about so im just nitpicking about issues out of context or something like that. just wondering. anyway, its been a while since i looked at java generics and tried them. what is the difference with <? extends T> and <? super T>? does the first require it to be a subtype of T and not allow the base type T? and the second one only differs by also allowing the base type T (here Shape)? OK I should probably google it for a quick answer but it seemed to me this could have used explanation in this entry. or maybe im just thick and missed it etc :)

good bloggin!