Generics PECS - [OOP & Java #11]
Tags: computerscience, java
Published: 2020-12-10 08:07:49

We will use the following code for ease of reference and discussion.

```java
// assignment
List<? extends Number> list1 = new ArrayList<Double>();
List<? super Integer> list2 = new ArrayList<Integer>();

// taking， suppose not empty
Number num1 = list1.get(0); // why works fine?
Integer num2 = list2.get(0); // why compiler-error?

// putting
list1.add(45); // why compiler-error?
list2.add(45); // why works fine?
```

#### Assignment
Assignment statements honor the invariance relationship of generics
```java
// ERROR
List<Number> list1 = new ArrayList<Double>();
// SAFE
List<Integer> list2 = new ArrayList<Integer>();
```
However, bounded wildcards provide two other kinds of relationship:

##### Covariance
- Upper bound wildcard parameterized type (`<? extends Number>`)
```java
// SAFE
List<? extends Number> list1 = new ArrayList<Double>();
```
##### Contravariance
- Lower bound wildcard parameterized type (`<? super Integer>`)
```java
// SAFE
List<? super Integer> list1 = new ArrayList<Number>();
```

Find out more from previous articles about generics if the above is not yet intuitive.

---

#### Accessing elements
So we know what can be assigned from the right-hand side to the left-hand side, now we can focus on what we can do with the product of that assignment. 

It's important to know that what is accessible from the variables like `list1` above depends on the information retained in the wildcard bound. 

Let's look at case 1: `? extends`
```java
List<? extends Number> list1 = new ArrayList<Double>();
```
- Take

`list1` has an unknown type of an upper bound `Number`. Following the fact of upper bounded wildcard that

> A returned object of "unknown" type is known to be compatible with the upper bound.

We know that we can retrieve objects of the upper bound type, `Number` in this case, from the list.
```java
// SAFE
List<? extends Number> list1 = new ArrayList<Double>();
Number num = list1.get(0) // suppose list1 is not empty
```
When we get to take things out of something, we call it a producer. Thus, we have the first half of PECS => **Producer Extends**.

- Put

However, because we cannot tell what is the unknown type that is inside `list1` (could be `Integer`, could be `Double`), we cannot put anything in, with the only exception being `null`.

```java
List<? extends Number> list1 = new ArrayList<Double>();
// ERROR
list1.add(1); 
// OK, but not useful
list1.add(null) 
```

---
Let's look at case 2: `? super`
```java
List<? super Integer> list2 = new ArrayList<Integer>();
```
- Take

`list2` has an unknown type of a lower bound `Integer`. This information is not enough to determine if `Integer` is inside `list2`. Thus, the only possible type of object that can be taken out is ... `Object`.
```java
List<? super Integer> list2 = new ArrayList<Integer>();
// ERROR
Number num = list2.get(0); // suppose not empty
Integer num = list2.get(0); // suppose not empty
// OK but not useful
Object num = list2.get(0);
```
- Put

The lower bound does provide us with the information that we can put an `Integer` into the list. This is because `Integer` is the lower bound, 
and hence:
- replacing `?` with `Integer`, 
- you get `List<Integer super *whatever super of Integer*>` 
- which will always be valid.

`<? super Integer>` means we can only assign `List<Integer>` or `List<Number>` or any supertype of `Integer` **for assignment**

But for putting/consuming stuff into the container, we can use any subtype of the lower bound. 
- `list2.add(45);` is fine
- `list2.add(new A());` is also fine, suppose `A extends Integer`

Here is the second half of PECS => **Consumer Super**.

---

We cannot pass/consume a `Number` into `list2` because the compiler does not know whether the `List<? super Integer>` refers to `List<Number>` or perhaps to a `List<Comparable<Integer>>`, in which case 
- `Number` should not go into `ArrayList<Comparable<Integer>>`
- and similarly `Comparable<Integer>` should not go into `ArrayList<Number>`

To elaborate:
- `Number` is a class that fits the requirement i.e. `List<Number super Integer>`
- `Comparable<Integer>` is an interface that fits the requirement, i.e. `List<Comparable<Integer> super Integer>`.
This means the following works for assignment calls, like we said before:
```java
List<? super Integer> l1 = new ArrayList<Number>();
List<? super Integer> l2 = new ArrayList<Comparable<Integer>>();
```
So, in the two possible cases above, what is the common type that can be added to both lists and still make sense?

The answer is `Integer` (and subtype of `Integer`).

#### Conclusion
Truth is I write this so that I can refer to it when I need it someday :smirk:
![image](https://user-images.githubusercontent.com/41845017/100529832-37213000-3226-11eb-977e-b639af77623c.png)
---

#### References:
Generics [FAQ here](http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#Which%20methods%20that%20use%20the%20type%20parameter%20in%20the%20argument%20or%20return%20type%20are%20accessible%20in%20an%20upper%20bound%20wildcard%20instantiation?) and [FAQ here](http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#Which%20methods%20that%20use%20the%20type%20parameter%20in%20the%20argument%20or%20return%20type%20are%20accessible%20in%20a%20lower%20bound%20wildcard%20instantiation?)