This discussion is archived
5 Replies Latest reply: Jun 7, 2012 6:06 AM by 800357 RSS

Generic subtyping

800357 Newbie
Currently Being Moderated
Hi,

Given this class declaration:
public class QMap<T> implements QFunction<T> {
     
     protected List<Option<? super T>> optionPool;
     
     public QMap( Option<? super T> o ) { ... }
     
     public QMap(List<Option<? super T>> optionList) { ... }
...
}
This (snippet 1) works:
  Option<Number> o;
  QMap<Double> testMap = new QMap<Double>( o );
But this (snippet 2) doesn't:
  List<Option<Number>> testPool = new ArrayList<Option<Number>>();
  QMap<Double> testMap = new QMap<Double>( testPool );
Compiler says: The constructor QMap<Double>(List<Option<Number>>) is undefined.

I can fix it like so (snippet 3):
          List<Option<? super Double>> testPool = new ArrayList<Option<? super Double>>();
          QMap<Double> testMap = new QMap<Double>( testPool );
But I thought snippet 2 should work, and moreover declaring testPool like in snippet 3 annoys me because I know what kind of Options I will put in there just fine. I can see why a List<Option<Number>> is not the same as a List<Option<? super Double>> nor a subtype of it, since a List<Option<? super Double>> could also be a List<Option<Object>>, for instance. Ok I guess I understand it on a practical level, but why was it designed this way? It doesn't make any sense.
  • 1. Re: Generic subtyping
    936584 Newbie
    Currently Being Moderated
    Hi matt32,

    You could change your constructor this way:
         public QMap(List<? extends Option<? super T>> optionList) {
              
         }
    And now you can use your snippet 2 as you expected:
    List<Option<Number>> testPool = new ArrayList<Option<Number>>();
      QMap<Double> testMap = new QMap<Double>( testPool );
    But I don't completely understand why this works this way, like you, I'll wait for some answer that clarifies this.
  • 2. Re: Generic subtyping
    800357 Newbie
    Currently Being Moderated
    Thanks for that, although I also still don't understand why that should work and the original constructor not. Any further input on this would be appreciated.
  • 3. Re: Generic subtyping
    800357 Newbie
    Currently Being Moderated
    An update. This also doesn't work:
    List<Option<Double>> testPool = new ArrayList<Option<Double>>();
      QMap<Double> testMap = new QMap<Double>( testPool );
    Compiler says:
    The constructor QMap<Double>( List<Option<Double>> ) is undefined
    Surely this should work?? Is this a bug? I'm using JDK 7u4 in Eclipse Indigo.
  • 4. Re: Generic subtyping
    805574 Newbie
    Currently Being Moderated
    No that shouldn't work. The <? extends T> vs <? super T> can be very tricky.

    The place to start would be the generics tutorial, specifically wildcards and more wildcards.
  • 5. Re: Generic subtyping
    800357 Newbie
    Currently Being Moderated
    Okay, I thought about this some more and I get it now; it's basically because of what I said in my original post. The reason it doesn't work is the same as the reason why
     List<Object> lo; List<String> ls; lo = ls; 
    doesn't work. I could add random stuff into lo, which wouldn't be Strings. Therefore I need to declare
    List<? extends Object> lo;
    Now lo has become read-only and I can work with it without any risk.

    Same for my case:
    List<Option<? super Double>> l1;
    List<Option<Number>> l2;
    l1 = l2; //compiler error: type mismatch
    Because I could add an Option<Object> into l1, or any other Option<supertype of Double> that is not an Option<Number>. Therefore I need to declare
    List<? extends Option<? super Double>> l1;
    Note that
    List<? super Option<? super Double>> l1;
    doesn't work, although I'm not sure why (since an Option is both a sub and supertype of an Option).

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points