• 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 all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Bear Bibeault
  • Devaka Cooray
  • Liutauras Vilda
  • Jeanne Boyarsky
Sheriffs:
  • Knute Snortum
  • Junilu Lacar
  • paul wheaton
Saloon Keepers:
  • Ganesh Patekar
  • Frits Walraven
  • Tim Moores
  • Ron McLeod
  • Carey Brown
Bartenders:
  • Stephan van Hulst
  • salvin francis
  • Tim Holloway

Upper and Lower Bounded Wildcard Question (Generics)  RSS feed

 
Ranch Hand
Posts: 49
1
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Greetings all,

I'm Having a few issues understanding something regarding Upper and Lower Bounded Lists and would really appreciate if someone could help me understand what's going on here!!

Let's say I have a simple class hierarchy: Building > Residential > House > SemiDet (SemiDet extends House, House extends Residential and Residential extends Building).

Then let's say I create a List with a Lower Bounded type...



Now, the type of the above List can only be Residential or Building.  So, let's say I now create another List reference (this time Upper Bounded) to which I will attempt to assign my first List...



I'm trying to figure out why the above fails to compile.  The type of of upperBList can be either Building, Residential, House or SemiDet and lowerBList can be either Residential or Building, so should this not be assignable?

In other words, all of the following are valid...



Am I missing something!?

Thanks all, appreciate any advise that could improve my understanding :-)
 
Rancher
Posts: 3309
33
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

fails to compile


Please copy the full text of the error message and paste it here. It has important info about the error.
 
Stephen Bell
Ranch Hand
Posts: 49
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sure, the compiler throws this at me...

incompatible types: List<CAP#1> cannot be converted to List<? extends Building>
where CAP#1 is a fresh type-variable: CAP#1 extends Object super: Residential from
capture of ? super Residential



Many thanks
 
Master Rancher
Posts: 3001
105
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
If there's anything incomprehensible, then it is the errors when it comes to Generics...

Better (but sometimes failing) is to try to reason about it. Takes a lot of practising, but the reward is good.

If you have:

then, as far the compiler is concerned, lowerBList could be of type Residential, Building OR Object. So the compiler cannot guarantee that in

the '? extends Building' is correct, and therefore it won't compile.

It all boils down to the reference type. For instance, can you predict whether this will compile:


Your examples do compile:


But can you predict if you can add an element to one of the upperBLists? Why or why not?
 
Stephen Bell
Ranch Hand
Posts: 49
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Piet and many thanks for the reply!

Yes, I've been starting at the compiler message for ages and I can't figure it out.

I realise that the last 4 examples I gave compile OK - that's what was confusing me, they seem to be equivalent to the line that doesn't compile (ie, all the possible types of 'lowerBList' are valid for 'upperBList' (or so it seems)).  I know that list with upper bounds are not modifiable (well, apart from clearing it or removing elements). But I just can't understand for the life of me why the assignment doesn't compile - it's very confusing :-(

the 'So the compiler cannot guarantee that '? extends Building' is correct, and therefore it won't compile.



Could you clarify this part for me please?

Many thanks for your help, really appreciate it!
 
Piet Souris
Master Rancher
Posts: 3001
105
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I hope so!
'
We have the series Object -> Building -> Residential.
So '? super Residential' is either an Object, a Building or a Residential.
Therefore, List<? super Residential>' could be a List<Object>, and so a List<? extends Building> can not be a List<? super Residential>.
 
Stephen Bell
Ranch Hand
Posts: 49
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Piet,

I think I just got what you mean :-)

I'm forgetting about 'Object' and not factoring that in, so in fact, upperBList isn't compatible with all possible types of lowerBList because lowerBList also includes 'Object'?!

Thank you so much  for pointing that out - I can't believe I didn't see it, I've been trying understand this for hours!!

Regards
 
author
Posts: 23805
140
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Stephen Bell wrote:
Then let's say I create a List with a Lower Bounded type...




Slight Detour...

Can someone with deep knowledge of generics explain this one? First, it is using the diamond operator. This means that the type of the generics (that is being instantiated) is inferred. However, it is also using the wildcard. So, what is the type of the generic? How is it inferred? I have seen code like this before, and this always bothered me....

Henry
 
Piet Souris
Master Rancher
Posts: 3001
105
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Admitted: this is exactly the weak part of my theory...

But if you have
then
also fails. It is not clear to me what the compiler does with things like ? super/extends, so I try to avoid these things if that is at all possible.
 
Stephen Bell
Ranch Hand
Posts: 49
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Henry Wong wrote:

Can someone with deep knowledge of generics explain this one? First, it is using the diamond operator. This means that the type of the generics (that is being instantiated) is inferred. However, it is also using the wildcard. So, what is the type of the generic? How is it inferred? I have seen code like this before, and this always bothered me....



That's interesting because I've wondered this too!  I've always assumed that the inferred type of the instantiated ArrayList is the actual Upper/Lower bound, so in the following example...



I've always assumed the inferred type is 'Residential' - can anyone confirm this?
 
Bartender
Posts: 9487
184
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It's very simple. The diamond operator just removes the wildcard. In Java 9, this compiles:

Whereas the following doesn't:
 
Stephan van Hulst
Bartender
Posts: 9487
184
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Piet Souris wrote:But if you have [...] then [...] also fails.


That's because myList could be of any type that is a super-type of Residential, including List<Object>. You can't assign a List<Object> to a List<Residential>, so the compiler complains.

It is not clear to me what the compiler does with things like ? super/extends, so I try to avoid these things if that is at all possible.


That's a pity. Wildcards make your libraries much more flexible and easy to use. You should use them as much as possible.
 
Henry Wong
author
Posts: 23805
140
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:It's very simple. The diamond operator just removes the wildcard. In Java 9 ....



Wow. I was thinking that it doesn't really matter anyway, as the generic type is immediately lost. I completely forgot about anonymous inner classes...  

Have a couple of cows,
Henry
 
Piet Souris
Master Rancher
Posts: 3001
105
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:

Piet Souris wrote:But if you have [...] then [...] also fails.


That's because myList could be of any type that is a super-type of Residential, including List<Object>. You can't assign a List<Object> to a List<Residential>, so the compiler complains.


That's right, but it would have been possible for the compiler to conclude that in
List<? super Residential> list = new ArrayList<Residential>();
the left part (? super Residential) could only be Residential, but that is obviously not what is happening.

Stephan van Hulst wrote:That's a pity. Wildcards make your libraries much more flexible and easy to use. You should use them as much as possible.


In many examples of yours I noticed your use of wildcards, where I would not have used them. I guess that in your profession you are dealing much more with this subject than I do. I guess it is also something to get used to. I wil try to make more use of this in the future!
 
Stephan van Hulst
Bartender
Posts: 9487
184
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Piet Souris wrote:That's right, but it would have been possible for the compiler to conclude that [..] the left part (? super Residential) could only be Residential, but that is obviously not what is happening.


Well, sure. It would be possible. You're asking a LOT of the compiler though. It's comparable to the following case:

Sure, the compiler COULD reason that y is a compile time constant, but the compiler code is significantly more complex than it is when compile time constants are defined to be just those final variables that are initialized as they're declared. In the case of the generic list, you're asking the compiler to keep track of the generic type argument as it passes through the code. Why should it do that, if you can much more easily just use the formal type you want to use?

I guess that in your profession you are dealing much more with this subject than I do. I guess it is also something to get used to. I wil try to make more use of this in the future!


Not really. Professionally I work with C#, which has declaration site variance, as opposed to Java, which has use site variance. I don't write generic types so much that I encounter lots of type bounds in my C# code. Java I use for my hobby projects.

Make sure to use them in the future, challenging yourself is the best way to learn. If you run into problems, let us know.
 
Stephen Bell
Ranch Hand
Posts: 49
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Just out of interest, I've noticed that the opposite will not compile (assigning a Upper-Bounded ArrayList to a Lower-Bounded List reference) even when I would expect it too...

   

So, the above list can only really be of type 'SemiDet' as that is the 'lowest' class in my hierarchy, ie, it has no subclasses.  Now, if I try this...

   

... it doesn't compile even thought 'upperBoundedList' must be of type 'SemiDet' and 'lowerBoundedList' can assign an ArrayList with a type of SemiDet all the way up to 'Object'.

I think I understand why, but I'd like to run it by you guys, I think it's because although SemiDet has no subclasses, the compiler doesn't take this into consideration.  Because I've declared my upperBoundedList with a Upper Bounded wildcard, <? extends SemiDet> it just assumes that subclasses could exist and therefore won't allow me to assign it. (say I had a TwoBedSemiDet that extended SemiDet, then upperBoundedList could be of type TwoBedSemiDet which obviously wouldn't be assignable to my lowerBoundedList reference (as its lower bounds is SemiDet).

It's odd though that it still doesn't compile even if I make SemiDet final and therefore exclude the possibility of subclassing it.

As alway thanks for your valuable help! :-)
 
Sheriff
Posts: 23866
50
Eclipse IDE Firefox Browser MySQL Database
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Stephen Bell wrote:So, the above list can only really be of type 'SemiDet' as that is the 'lowest' class in my hierarchy, ie, it has no subclasses.



I don't believe the compiler will look through your class hierarchy to find out whether a class has any subclasses. Why not? Because I could write a subclass of SemiDet and use it with your software. Or you could write one yourself next week.

Okay, so you say your SemiDet class is final so I can't do that? I still don't believe the compiler will care about that either -- but I haven't tried to see if that makes a difference.
 
Stephen Bell
Ranch Hand
Posts: 49
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Paul Clapham wrote:
I don't believe the compiler will look through your class hierarchy



Thanks Paul, yes I agree that is probably the case, I just wanted to make sure I was on the right page and understanding things.  It just confused me because I know when casting objects the compiler does seem to look through the hierarchy and making classes final can affect whether the compiler will allow something to compile or throw an error.  I thought it might be the same when using Generics but I guess not.

Thanks very much!!
 
Marshal
Posts: 6254
420
BSD
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stephen Bell, cowgratulations, your topic have been chosen to publish in CodeRanch's Journal April Edition.
 
Stephen Bell
Ranch Hand
Posts: 49
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
That's awesome!  
 
Sheriff
Posts: 12738
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
See Get/Put Principle for generics wildcards and Josh Bloch's PECS Rule (Producer Extends, Consumer Super) http://thegreyblog.blogspot.com/2011/03/java-generics-tutorial-part-iii.html
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!