0

Why the following method does not give a compiler error? :

    public void func3(List<? extends Number> l1, List<? extends Number> l2) {
        l1 = l2;
    }

Run-time error could occur in the method, but why the compiler thinks the static-type of l2 is the same as l1? ( hence, there's no compiler error )

jacob12
  • 173
  • 8
  • 2
    But... they're exactly the same parameterized type. Why do you think a compiler error should occur here? Note you can't _add_ to a `List extends Anything>`. – Slaw Jun 25 '22 at 05:13
  • Why their types are the same? since wildcards are used, their types could be anything that inherits from `Number`. It seems to me that the compiler decides this implicitly. If it were written `public void func3(List l1, List l2)` then I'd agree about `lst1` and `lst2` having the same types since we explicitly define it to be `T`. – jacob12 Jun 25 '22 at 05:22
  • 1
    I think you're confusing the static type of the parameters, and the "run-time type" of the arguments (though of course generics don't exist at run-time). The whole point of wildcards is to say, "The real type can be anything, so long as it's assignable to the upper bound(s)". So, both `l1` and `l2` are saying what matters is that the elements are assignable to `Number`, and what the actual type of the parameters is _does not matter_. Whenever you read an element _from either list_, all you know is that it's a `Number`. – Slaw Jun 25 '22 at 06:11
  • Thanks , didn't know this. Do you have any idea though what the parameterized type of `l1` and `l2` are in the above method?. Because of the wildcard it seems that we can't know, but all we can know is that the type will be assignable to `Number`. – jacob12 Jun 25 '22 at 06:28
  • The parameterized type _is_ `List extends Number>`. The generic type argument is `? extends Number`. That's a type, and it says, "Something that is assignable to `Number`". The point of generics is to allow this sort of ambiguity regarding the "real" type, while maintaining a strong static type system. – Slaw Jun 25 '22 at 06:31
  • 1
    Since I deleted one of my comments, here's the link to the Q&A I had: [What is PECS (Producer Extends Consumer Super)?](https://stackoverflow.com/questions/2723397/what-is-pecs-producer-extends-consumer-super). It won't necessarily answer your question, but understanding the concept of PECS may help. Both of your lists are "producers of `Number`". – Slaw Jun 25 '22 at 06:37

1 Answers1

3

but why the compiler thinks the static-type of l2 is the same as l1? ( hence, there's no compiler error )

Because they are exactly the same. The compile-time type of the variables l1 and l2 are both List<? extends Number>.

Run-time error could occur in the method

No, runtime error cannot occur. The assignment is completely safe. Anything that can be pointed to by the type of l2 can be pointed to by the type of l1.

since wildcards are used, their types could be anything that inherits from Number.

I think you are thinking of the fact that, for example, you can pass a List<Integer> as first argument and a List<Double> as second argument. Yes, and that's perfectly fine. Then l1 will point to the List<Integer> and l2 will point to the List<Double>. Then when you do l1 = l2;, you make both l1 and l2 point to the List<Double>. And that's fine. Since l1 has type List<? extends Number>, it can sometimes point to a List<Integer> and at other times point to a List<Double>. Consider a simpler example:

public void func4(Object o1, Object o2) {
    o1 = o2;
}

I can pass a String as first argument and an Integer as second argument, and that's perfectly fine. The assignment o1 = o2; will cause both o1 and o2 to point to the Integer object, and o1 and o2 can do that since they have type Object.

newacct
  • 119,665
  • 29
  • 163
  • 224