After reading your email again, I find myself agreeing.  This is because I
don't consider List<Integer> to be a subtype of List<Number>.

LinkedList<Number> would be a subtype of List<Number>, but inheritance
doesn't really extend any further beyond that, for the reason you have
illustrated.

The example you gave is similar to implementing an interface with a type
hint of Number, but trying to changing it to Integer.  The method
signatures are clearly incompatible, so I believe the same applies here in
generics.
On 29 Apr 2016 4:22 p.m., "Rowan Collins" <rowan.coll...@gmail.com> wrote:

> guilhermebla...@gmail.com wrote on 29/04/2016 15:26:
>
>> You can add subtypes of A to a List<A> in Java. What List<? extends A>
>>> >means is that the list itself may be a list of any type, provided that
>>> type
>>> >is compatible with A. So if B extends A, List<B> is compatible with
>>> List<?
>>> >extends A>, and when reading items you can assume they will be
>>> compatible
>>> >with A (since B extends A) but you can't add an A (because it's
>>> actually a
>>> >list of Bs).
>>> >
>>> >
>>>
>> Wrong. This is documented here
>> https://docs.oracle.com/javase/tutorial/java/generics/upperBounded.html
>> and
>> specifically states:
>>
>> To write the method that works on lists of Number and the subtypes of
>> Number,
>>
>>> >such as Integer, Double, and Float, you would specify List<? extends
>>> >Number>. The term List<Number> is more restrictive than List<? extends
>>> >Number> because the former matches a list of type Number only, whereas
>>> >the latter matches a list of type Number or any of its subclasses.
>>>
>>
>
> Forgive me for butting in if I'm completely wrong, but is the confusion
> here between *declaring an instance* and *declaring a parameter constraint*?
>
> I think the point is that you can declare variables as follows:
>
> List<Integer> li;  // only accepts Integer
> List<Double> ld; // only accepts Double
> List<Number> ln; // accepts any Number, even if it is in fact an Integer
> or Double instance
>
> But if you then define a function accepting a parameter:
>
> public static double sumOfList(List<Number> list)
>
>
> Now your argument has to be of type List<Number>; you can pass "ln" above,
> but not "li" or "ld". To relax the function's contract, you can write this
> instead:
>
> public static double sumOfList(List<? extends Number> list)
>
> Now the argument can be a List<Integer> or List<Double>, so "li" and "ld"
> are legal arguments.
>
>
> The reason the default case is to be invariant, rather than covariant, is
> explained on the blog post Jesse linked to:
> http://hhvm.com/blog/9215/covariance-contravariance-and-super-type-constraints
>
>
> In a nutshell, consider this function:
>
> function addPiToList(List<Number> $list): void
> {
> $list->add(3.1415); // for the sake of example, assume 3.1415 instanceOf
> Double
> }
>
> If we allow covariance, then we can run addPiToList(new List<Integer>) and
> the type conditions are met; clearly this is not sane, and is going to
> result in an error somewhere.
>
> So we need to be stricter:
>
> function addPiToList(List<Double> $list): void
>
> But the actual contract we want here is "any list we can legally add a
> Double to", and if we get a List<Number> or a List<*>, it would work fine,
> so our check is too strict. What's needed is a way to declare our function
> as contravariant:
>
> function addPiToList(List<? super Double> $list): void
>
> Now we can pass in a List<Double> or a List<Number>, but not a
> List<Integer>, and our contract holds nicely.
>
>
> It took me a while to get my head around, but I think the above makes
> sense...
>
> Regards,
> --
> Rowan Collins
> [IMSoP]
>

Reply via email to