Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / January 2006

Tip: Looking for answers? Try searching our database.

Bounded wildcards and type compatibility

Thread view: 
John C. Bollinger - 04 Jan 2006 14:49 GMT
Neither version 1.5.0_06 of Sun's compiler nor version 3.1.1 of
Eclipse's will compile the following code, but I can't figure out what's
wrong with it:

====

package test;

public class TestTypeBounds {

    public void foo(Bar<? extends Foo, Baz<? extends Foo>> bar) {
    }

    public <T extends Foo> void doFoo(Bar<T, Baz<? extends T>> bar) {
        foo(bar);  // <=== incompatible types here (?)
    }
}

class Foo {}

class Bar <X, Y> {}

class Baz <Z> {}

====

Both compilers complain about incompatible types in the invocation of
foo().  Eclipse's compiler seems to have fewer bugs related to
parameterized types than does Sun's (0 vs. 2 on my personal scorecard,
before this), but when both compilers reject the code it's a pretty good
sign that the code is wrong.  For the life of me, however, I don't see
the problem.  Does anyone else see anything wrong?

Signature

John Bollinger
jobollin@indiana.edu

John C. Bollinger - 04 Jan 2006 15:13 GMT
I wrote:

> Neither version 1.5.0_06 of Sun's compiler nor version 3.1.1 of
> Eclipse's will compile the following code, but I can't figure out what's
> wrong with it:

[...]

I finally had the flash of insight just after I posted.  It figures.
I'm now guessing that the situation is just a more complicated version
of Foo<Object> not being a supertype of Foo<String>.  Simplifying it a
bit, even though their type parameters match up fine individually,
Foo<?, ?> is not a supertype of Foo<T, T> because the relationship
between the type parameters in the latter type is not represented by the
former type.

Does that make sense?  I'm not quite sure it does -- I'm still not
seeing why Foo<?, ?> shouldn't be a valid generalization of Foo<T, T>.

Signature

John Bollinger
jobollin@indiana.edu

opalpa@gmail.com - 04 Jan 2006 15:33 GMT
Hello, should line

public <T extends Foo> void doFoo(Bar<T, Baz<? extends T>> bar) {

be

public <T extends Foo> void doFoo(Bar<T, Baz<? extends Foo>> bar) {

?

All the best!

opalpa@gmail.com
http://www.geocities.com/opalpaweb/
opalpa@gmail.com - 04 Jan 2006 16:09 GMT
I'm gonna try to talk out the code, that is convert the statements into
English.

Some of the easy stuff is that:

Bar is a class paramterized on two things.
Baz is a class paramterized on one thing.
Foo is not paramterized.

There are two methods left and that is the hairy stuff.
Let's look at the one invoked first:

doFoo has an argument which is a Bar  and we know that Bar is
paramterized on two things.  doFoo's Bar argument is paramterized on a
subclass of Foo and a Baz which is itself paramterized on a subclass of
a subclass of Foo (right?).  That does not make sense to me, T  extends
Foo and Baz is paramterize on ? extends T.  Does that mean that we need
a subclass of a subclass?

Could we write doFoo like so:

public <T extends Foo> void doFoo(Bar<T, Baz<T>> bar) {

Compiler does not accept it.  Why not?

It accepts:
public <T extends Foo> void doFoo(Bar<? extends Foo, Baz<? extends
Foo>> bar) {

But I cannot substitute "? extends Foo" with T.  Should that be the
case?

The generics stuff clearly opens up possibilites that are hard to think
about.  It's like C++ stuff.  Fortunately in practice code (my code
anyway) never gets to this point.  Generics in practice seem to be
conveniences for reducing typing casts.
John C. Bollinger - 04 Jan 2006 17:06 GMT
> I'm gonna try to talk out the code, that is convert the statements into
> English.
[quoted text clipped - 4 lines]
> Baz is a class paramterized on one thing.
> Foo is not paramterized.

Good up to here.

> There are two methods left and that is the hairy stuff.
> Let's look at the one invoked first:
[quoted text clipped - 5 lines]
> Foo and Baz is paramterize on ? extends T.  Does that mean that we need
> a subclass of a subclass?

No, you're missing an important point here.  doFoo's argument is
characterized a particular subclass of Foo, and on a Baz which is itself
characterized by a subclass of *the same* subclass of Foo.  The bound on
the method's type parameter doesn't really matter here, it turns out;
you could remove it altogether without fundamentally changing what I
intend to express.

> Could we write doFoo like so:
>
> public <T extends Foo> void doFoo(Bar<T, Baz<T>> bar) {

That means something different, but I could work with it if the compiler
would accept it.  As you observed (elided), it does not.  I have now
figured out why (see my most recent previous post), so now I just have
to determine how to handle the situation.

For what it's worth, this whole issue arose when trying to mangle
perfectly good generic code (that Eclipse handles fine) to work around
bugs in Sun's javac.  Why is it that Eclipse can handle Java generics
better than Sun itself can?

[...]

> The generics stuff clearly opens up possibilites that are hard to think
> about.  It's like C++ stuff.  Fortunately in practice code (my code
> anyway) never gets to this point.  Generics in practice seem to be
> conveniences for reducing typing casts.

I find it most useful to think about generics in terms of describing
types.  That seems trivial to say, but you are bound to run into trouble
when you lose sight of it.  Reducing casts, though touted as a major
benefit of generics, is just a side effect of the deep change in the
type system that generics bring.  Parameterized types are a whole
conceptual level higher than unparameterized ones, and thus they do
present considerably greater challenges.

Signature

John Bollinger
jobollin@indiana.edu

John C. Bollinger - 04 Jan 2006 16:47 GMT
> Hello, should line
>
[quoted text clipped - 5 lines]
>
> ?

Thanks, but no, it shouldn't.  Your proposed change means something
different from the original code.  It does not in any case solve the
problem, for I find that the type bounds aren't the issue after all.
For example, this version also doesn't compile:

====

package test;

public class TestWildcards {

    public void foo(Bar<Baz<?>> bar) {
    }

    public <T> void doFoo(Bar<Baz<T>> bar) {
        foo(bar);  // <=== Incompatible types here (still)
    }
}

class Bar <X> {}

class Baz <Z> {}

====

This version clarifies the problem, I think, to the extent that I can
now articulate it clearly.  It is true that Baz<T> is a subtype of
Baz<?>, but that does not make Bar<Baz<T>> a subtype of Bar<Baz<?>>, the
wildcard notwithstanding.  This is in fact correct, as it is exactly
analogous to List<Object> vs. List<String>.  Adding additional type
parameters to Bar makes it harder to identify the real issue, but
doesn't fundamentally change it.

Signature

John Bollinger
jobollin@indiana.edu

Torkel Franzen - 04 Jan 2006 16:57 GMT
> It is true that Baz<T> is a subtype of
> Baz<?>, but that does not make Bar<Baz<T>> a subtype of Bar<Baz<?>>, the
> wildcard notwithstanding.

 Yep. See the rules about containment in 4.5.1.1 and about subtyping
in 4.10.2.


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.