• 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

Generic wildcard puzzle

 
Ranch Hand
Posts: 234
12
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I'm trying to understand how generics works. I understand the basics but I find this puzzling. Can someone please help me solve this puzzle. I'd appreciate a "generics for dummies" explanation.  

This code compiles. I'm able to pass a List <? extends Number> and a List <? super Number> into this method static <T> void genericMethod(List<T> l)


This code does not compile. Why can't I pass a List <? extends Number> into this method static <T> void genericMethod(List<T> l, T t). Why am I able to pass a List <? super Number> but not a List <? extends Number>



The compiler error is

Generics.java:11: error: method genericMethod in class Generics cannot be applied to given types;
       genericMethod(list_extendsNumber, 1);// compiler error
       ^
 required: List<T>,T
 found: List<CAP#1>,int
 reason: inference variable T has incompatible bounds
   equality constraints: CAP#1
   lower bounds: Integer
 where T is a type-variable:
   T extends Object declared in method <T>genericMethod(List<T>,T)
 where CAP#1 is a fresh type-variable:
   CAP#1 extends Number from capture of ? extends Number
1 error
 
Saloon Keeper
Posts: 15510
363
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The compiler infers T from the t parameter. I don't have hard facts to back this up, but an experiment I once conducted suggests that the compiler looks at less nested types before more nested types. By this I mean that the compiler will first try to infer type arguments from parameters like T, then from parameters like GenericType<T>, and then from GenericType<GenericType<T>>, etcetera.

That means that in your second example, T is inferred to be an Integer, so it expects parameter l to be a List<Integer>. List<? extends Number> is not a subtype of List<Integer>, so you can't pass that as a method argument.
 
Daniel Cox
Ranch Hand
Posts: 234
12
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:That means that in your second example, T is inferred to be an Integer, so it expects parameter l to be a List<Integer>. List<? extends Number> is not a subtype of List<Integer>, so you can't pass that as a method argument.


Thanks for your reply Stephan.

List<? super Number> is also not a subtype of List<Integer> but I'm able to pass it as a method argument.
 
Marshal
Posts: 79177
377
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
List<? super Number> may contain Numbers or Objects. I think it is contravariant types. Try here and in the JLS link mentioned (which nobody else can understand either ‍), or search for “Angelika Langer Java generics FAQ”.
 
Stephan van Hulst
Saloon Keeper
Posts: 15510
363
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Sorry, I just realized my previous explanation was unrelated, please ignore.

Formal typeUpper boundLower bound
TObjectInteger
List<? super Number>ObjectNumber
List<? extends Number>NumberCAP#1

In this table you can see that all bounds match with T's bounds, except the lower bound of List<? extends Number>. The lower bound of List<? extends Number> is CAP#1, which is another way of saying: We don't know what the lower bound is, but it could be Integer, or Double, or Float or whatever else that extends Number.

What causes this asymmetry between super and extends? The reason is because upper bounds have a single hard limit: Object. No matter what the type is, everything is an Object. The compiler can't perform the same trick with lower bounds, because when you have a List<? extends Number>, there's no way of determining at compile time if its runtime type will be List<Integer> or List<Number> or List<Double> or whatever.
 
Stephan van Hulst
Saloon Keeper
Posts: 15510
363
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
In short: You would have the same problem with List<? super Number> if Java had types that aren't sub-types of Object.
 
Daniel Cox
Ranch Hand
Posts: 234
12
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:In this table you can see that all bounds match with T's bounds, except the lower bound of List<? extends Number>.


I think I'm beginning to see the picture but its still a little murky. Yes List<? extends Number> doesn't have a lower bound, but I wonder why the compiler can't infer the type parameter as Number since it matches both arguments.

 
Stephan van Hulst
Saloon Keeper
Posts: 15510
363
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The upper bounds of all arguments must be compatible, and the lower bounds of all arguments must be compatible.

For List<? super Number> and Integer, the upper bounds are compatible (Object and Object) and the lower bounds are compatible (Integer and Number).

For List<? extends Number> and Integer, the upper bounds are compatible (Object and Number) but the lower bounds are not (Integer and CAP#1). Regardless of what T is, it's possible that CAP#1 is Double:
 
Daniel Cox
Ranch Hand
Posts: 234
12
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks a lot Stephan.  
 
No matter how many women are assigned to the project, a pregnancy takes nine months. Much longer than this tiny ad:
a bit of art, as a gift, that will fit in a stocking
https://gardener-gift.com
reply
    Bookmark Topic Watch Topic
  • New Topic