Genericshard5-8 years

A generic `copyAll(Collection<T> from, Collection<T> to)` method fails to compile when called with a `List<Integer>` source and a `List<Number>` destination, even though copying integers into a list of numbers is obviously safe. Fix the signature, and explain exactly why each wildcard you add is necessary — not just "PECS," the actual reasoning.

The original signature requires from and to to have the exact same type argument T, because generic types are invariant — List<Integer> is not a List<Number>, even though Integer is a Number, precisely so that writing a Double into what the compiler thinks is a List<Integer> through a wider reference can never happen. But copyAll doesn't actually need from and to to share one type; it needs from's elements to be assignable to whatever to accepts. The fix is Collection<? extends T> from, Collection<? super T> to: from only ever gets read from, so it can be any collection of T or a subtype (? extends T, a "producer"), and to only ever gets written to, so it can be any collection of T or a supertype (? super T, a "consumer"). That's PECS — producer extends, consumer super — and it's not an arbitrary mnemonic, it's a direct consequence of what each wildcard permits: you can read a guaranteed-safe upper bound out of an extends wildcard, and you can write a guaranteed-safe value into a super wildcard, and neither wildcard lets you do the opposite.

The lesson behind it →
More on Generics