nus-cs2030 / 2021-s2

2 stars 2 forks source link

Regarding generics #104

Open ShyamalSankar opened 3 years ago

ShyamalSankar commented 3 years ago

Hello in lectures we were taught to write map functions like this: (some return type) map(Function<? super T, ? extends R>)

I understand why we need the ? super T in order to take in any functions that work with a super class of T. But what is the point of the ? extends R? Why can't we just write Function<? super T, R> since the type of would be determined based on the function that is passed in?

Thank you!

ryo-wijaya commented 3 years ago

If I'm not wrong, the point of using ? super and ? extends is to force the covariance nature of how superclasses and classes should work (as Generics are invariant).

You need ? extends R in the map method as you should be able to map an element to one of its sub-classes, but not the other way round.

Taking the example in the lecture, say you have 3 classes. FastFood, Burger extends FastFood, Cheeseburger extends Burger

As you can see, Cheeseburger <: Burger <: FastFood

Say you want to use the map method to perform a transformation from a list of Burgers to something else and assign it to a list of Burgers. You should be allowed to assign a Cheeseburger into the Burger list, and not a FastFood into a Burger list, as a sub-class should have the functions of it's parent and not vice versa.

Therefore, you should be allowed to write a function Function<Burger, Cheeseburger> lambda = x -> new Cheeseburger(x.burger()) //lets say x.burger returns its ID

Therefore, this assignment below should be allowed as it makes sense. List<Burger> list = burgers.map(lambda)

As all the method you can use in a Burger can also be used in a Cheeseburger

If you write Function<? super T, R>, for this scenario your return type can only be a Burger and you can only write Burger to Burger functions.

Martini-Chwang commented 3 years ago

? extends R allows the function to return any subclass of R, thus making the function more 'general'. This is similar for ? super T, allowing the function to take in anything that's the super class of T, thus being a bit more flexible in its use.