Generics: Why bounded wildcards?

A

Aquila Deus

Hi all!

I just read sun's generics-tutorial.pdf, it says that, for example, if
you have:

public class Shape;
public class Circle extends Shape;

AND

public void drawAll(List<Shape> shapes);

AND you want to pass List<Circle> to drawAll(), you should use:

public void drawAll(List<? extends Shape> shapes);

instead.

Would somebody explain to me why it is that? Shoulnd't the "Shape" in
the first drawAll() definition imply all types derived from "Shape"??
 
R

Ryan Stewart

Aquila Deus said:
Hi all!

I just read sun's generics-tutorial.pdf, it says that, for example, if
you have:

public class Shape;
public class Circle extends Shape;

AND

public void drawAll(List<Shape> shapes);

AND you want to pass List<Circle> to drawAll(), you should use:

public void drawAll(List<? extends Shape> shapes);

instead.

Would somebody explain to me why it is that? Shoulnd't the "Shape" in
the first drawAll() definition imply all types derived from "Shape"??
If you read the tutorial fully, you should know that the answer is no. It's all
explained quite thoroughly.
 
C

Chris Uppal

Aquila said:
I just read sun's generics-tutorial.pdf, it says that, for example, if
you have:

Unfortunately, just as I was about to reply with a link to that tutorial, I
re-read your question and saw that you already had it. That's a pity because
it's a reasonably clear explanation (IMO) though it needs a couple of readings
to make it settle. Try reading it again in a day to two.

public class Shape;
public class Circle extends Shape;

AND

public void drawAll(List<Shape> shapes);

AND you want to pass List<Circle> to drawAll(), you should use:

public void drawAll(List<? extends Shape> shapes);

instead.

Would somebody explain to me why it is that? Shoulnd't the "Shape" in
the first drawAll() definition imply all types derived from "Shape"??

Yes (in the sense I think you mean, anyway), but that only means that an
instance of Circle can be used anywhere where an instance of Shape is expected.
The same is /not/ true of Lists-of-Circles and Lists-of-Shapes.

If you use a List-of-Circles in a context where a List-of-Shapes is expected,
then it will break if the user of the (it thinks) List-of-Shapes decides to add
another Shape to the list. E.g. it might try to add a Triangle. As far as the
user of the List-of-Shapes is concerned, that is perfectly reasonable thing to
do, and should be legal. But the problem is that the list is /really/ a
List-of-Circles and its just not allowed to add Triangles to it.

That makes a problem for the type system. In a way it would seem to be
perfectly natural to allow a List-of-Circles to be used wherever a
List-of-Shapes is expected. That's because when you /read/ an item from the
list, expecting a Shape, you actually get a Circle, and that's all OK -- just
as it should be. The problem comes when you are allowed to add things to the
list.

So there are two ways out. One is to add some kind of mutability ("const" or
"readonly") declaration to the Java language. If that were added, then you
could indeed use a List-of-Circles wherever a List-of-Shapes was expected,
PROVIDED that the reference was "readonly".

Instead the Java designers decided to use the "wildcard" concept. I'm not sure
why since it seems to be more limited in scope, /and/ more convoluted in
application (though I'm sure the decision was not taken lightly). It has
roughly the same effect. By using a wildcard you are saying it's a
"List-of-Something(I don't know what the hell it is, exactly, but I /do/ know
that it extends Shape)". So you (the compiler's type checker) doesn't know
exactly what type of things to expect to find on the list, but it does know
that they all inherit from Shape, which means it's OK to read Shapes from the
list. But, since it doesn't know the precise type of the list, it has no idea
whether adding, say, a Triangle would be legal (it would be legal if the
"Something(I don't know what...)" were Shape, or Triangle, or Polygon, but not
it were Circle). Since the compiler can't prove to itself that modifying the
list is legal, it forbids it.

Simple ! Well, no -- I don't think it is simple. But maybe the above will
help the tutorial make sense when you next go over it.

-- chris


P.S. Not replying to the original question, but I can't help adding this
observation (or rant) for anyone who's interested: all the above complexity is
the result of a completely unnecessary (IMO) obsession with static type rigour.
The development type wasted ("wasted" IMO, of course) in creating this generics
system, plus the time that will be wasted by programmers learning to understand
and use it, plus the time that we will all waste creating/reading
complex/obscure generics declarations, could and (IMO) should have been put to
better use.
 
J

John C. Bollinger

Chris said:
That makes a problem for the type system. In a way it would seem to be
perfectly natural to allow a List-of-Circles to be used wherever a
List-of-Shapes is expected. That's because when you /read/ an item from the
list, expecting a Shape, you actually get a Circle, and that's all OK -- just
as it should be. The problem comes when you are allowed to add things to the
list.

So there are two ways out. One is to add some kind of mutability ("const" or
"readonly") declaration to the Java language. If that were added, then you
could indeed use a List-of-Circles wherever a List-of-Shapes was expected,
PROVIDED that the reference was "readonly".

Instead the Java designers decided to use the "wildcard" concept. I'm not sure
why since it seems to be more limited in scope, /and/ more convoluted in
application (though I'm sure the decision was not taken lightly). It has
roughly the same effect.

You're missing half the point. The OP asked about upper-bounded
wildcards, which permit typesafe polymorphic reading of values whose
specific class is not known, and for which a "const" or "readonly"
specifier might be an alternative, all as you described. But generics
also provide for lower-bounded wildards, which permit typesafe
polymorphic _writing_ of values whose specific class is not known. For
example:

void addCircle(List<? super Circle> circleList) {
circleList.add(new Circle(7, 7, 7));
}

There you know that whatever the component type of the List is, it is a
superclass of Circle (or is Circle itself), so it is safe to add a
Circle or an instance of any subclass. A "const" or "readonly" modifier
does nothing for you there, and it is not sufficient to just type the
argument as List<Circle>, as you already explained to the OP.


John Bollinger
(e-mail address removed)
 
C

Chris Uppal

John said:
So there are two ways out. One is to add some kind of mutability
("const" or "readonly") declaration to the Java language. If that were
added, then you could indeed use a List-of-Circles wherever a
List-of-Shapes was expected, PROVIDED that the reference was "readonly".

Instead the Java designers decided to use the "wildcard" concept. [...]

You're missing half the point.

I am ? I thought I was talking about the case that Aquila asked about.

The OP asked about upper-bounded
wildcards, which permit typesafe polymorphic reading of values whose
specific class is not known, and for which a "const" or "readonly"
specifier might be an alternative, all as you described. But generics
also provide for lower-bounded wildards, which permit typesafe
polymorphic _writing_ of values whose specific class is not known.

Agreed. I considered talking about write-only contexts too, but decided not to
add that to the post (partly to avoid piling on complexity, but also because I
am not yet confident enough of my grasp of generics to want to spout on /all/
details of the subject ;-)

-- chris
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top