• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

generics - incompatible types

 
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I thought I more or less understand generics, but I don't get why the following doesn't compile:



The error I get is

^

Eclipse "quick fixes" the second line to



which isn't really satisfactory. Is there any better solution?
 
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
This works:

Can't say I really understand why though.
 
Ranch Hand
Posts: 961
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Map.Entry is an interface, hence, Map.entrySet() actually implements a new Map.Entry.

Then, you're a actually receiving <? extends Map.Entry> and not Map.Entry itself.

Actually, reviewing the Tiger source code I discovered that HashMap has static nested class named Entry which hides that declard in the Map interface. This static nested class named Entry implements Map.Entry.

At least that�s what I think.

I had a hard time trying to figure it out, too. If somebody has another reasoning regarding this issue, please post it. I would like to read it.

Best regards,
Edwin Dalorzo.

[ April 11, 2006: Message edited by: Edwin Dalorzo ]
[ April 11, 2006: Message edited by: Edwin Dalorzo ]
 
Jim Yingst
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
But this works fine:

Much nicer. Map.Entry is still an interface, and there's no problem. It's just when we have wildcards that extra ugliness ensues.

I believe this relates to the rules for capture conversion, and specifically to the statement that "Capture conversion is not applied recursively." Capture conversion doesn't apply if the ? is nested within multiple < > braces. So it's necessary to introduce an additional ? within the outermost < >, to allow capture conversion to work.

That's the reasoning according the the JLS rules, I think. But I haven't really absorbed why it's necessary here.
[ April 11, 2006: Message edited by: Jim Yingst ]
 
Edwin Dalorzo
Ranch Hand
Posts: 961
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yeah, now I remember that rule. I have been trying to remember it the whole morning.

I read about these rules in the Java Programming Language Book like a couple of months ago. And I have to confess that I had completely forgotten about it.

Damn, I will have to dust it off out of my library now that I get back home.

I am really having difficulty learning all the oddities of generecy. From time to time I always face something I simply cannot understand, like this.

I think you are probably right, Jim. I will not rest until I can really master this generics stuff.

Thanks!
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Jim Yingst:

I believe this relates to the rules for capture conversion, and specifically to the statement that "Capture conversion is not applied recursively." Capture conversion doesn't apply if the ? is nested within multiple < > braces. So it's necessary to introduce an additional ? within the outermost < >, to allow capture conversion to work.



Yes, this sounds as if it's the problem. And as you, I'm not sure how it works this way - have to think a little bit more about it.

Anyway, thanks for the solution provided above!
 
Edwin Dalorzo
Ranch Hand
Posts: 961
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Ok, I have like an hour reading generics stuff. I think Jim was completely right. This is about violating the rules of capture conversion:

From The Java Programming Language, Fourth Edition


[...] you can oly apply capture conversion if the type variable is defined at the top-level of the generic type [...] suppose you have the method:

static <T> void processListOfLists(List<List<T>> list)

and you tried to invoke it with an argument of type List<List<?>>. The capture will not uniquely determine the an element type for the outer list [...]



I did some test of my own this time. I created this generic class:



And then I wrote som code. Note how data type is directly infered. In this case ther is not capture conversion.



However in this second case capture conversion infers "capture of ? super String" as Object:



Then I changed the Rancha class to contain a list of lists, like this:



And repeat the first test again.

This code compiles:



But in the case where capture conversion should be applied, just like inthe previous test, compiling fails: Type mismatch: cannot convert from List<List<capture-of ? super String>> to List<List<? super String>



So, unless once again I am wrong, this should prove you right, Jim.

Best regards,
Edwin Dalorzo.
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
But the question remains: *why* does it work this way?
 
Edwin Dalorzo
Ranch Hand
Posts: 961
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Well, I cannot be certain, but I believe that capture conversion just applies to the capture (?) and not to the extension mechanism (... extends X).

Capture conversion is an attempt of the compiler to infer the type of the capture.

In order words <? extends List<List<? super String>> is interpreted as
"capture of ? that extends some complex type X". And the complex type X will not be evaluated for capture conversion, because the system can already infer what the type of the capture is, which in this case is X, whatever it means (in this case List<List<? super String>>.

I ran some tests and concept survided.

At least that's what I think. However I still have a couple of questions. If I can figure out something else, I will post it later.



Best regards,
Edwin Dalorzo.

[ April 12, 2006: Message edited by: Edwin Dalorzo ]
[ April 12, 2006: Message edited by: Edwin Dalorzo ]
 
Edwin Dalorzo
Ranch Hand
Posts: 961
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Look at this variation of the same case.

In this example I cannot add an element to the list of lists. It is a violtion of the same rule about nested type parameters.

The outer list is required that all the elements are of the same type. In this case capture conversion is impossible. This happens because capture conversion cannot infer the actual type of the outer List when the actual type of the inner list is List<? super String>

That means that the outer list could contain many different kind of lists, like a List<Object>, a List<CharSequence> or a List<String>.

However, capture conversion cannot assume any of this types, because it would make the outter list incompatible for all the others.

In other words if capture conversion interprets List<List<? super String>> as List<List<Object>> then we could not add a List<String> or a List<CharSequence> to the outer List.

Hence, capture conversion fails because it is incapable of assigning a compatible type with all posible lists to the outer List



The truth is that I have some difficulty assimilating this rules.

Regards,
Edwin Dalorzo
 
Java Cowboy
Posts: 16084
88
Android Scala IntelliJ IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
OK, I didn't dive into the details of this question, but you might find an answer in Angelika Langer's Java Generics FAQ.
 
Ranch Hand
Posts: 1170
Hibernate Eclipse IDE Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Edwin, you cant add anything to a list of unknown type. Even if the type is narrowed down. So its not surprising that you can't to the list. Furthermore, that is not a 'collection' thing. That applies to any objects methods if the object is referred to by a wildcard.

I'm struggling with this question. Was there a consensus reached on this one? I can't find any solid answers on google or in any FAQs either.
 
Look! I laid an egg! Why does it smell like that? Tiny ad, does this smell weird to you?
a bit of art, as a gift, that will fit in a stocking
https://gardener-gift.com
reply
    Bookmark Topic Watch Topic
  • New Topic