Slide 1

Slide 1 text

Demystifying Co, Contra, In Kotlin A Lightning Presentation (support slides 2023) By João Esperancinha (2024/03/15)

Slide 2

Slide 2 text

Who am I? ● Software Engineer for 10+ years ● Java, Kotlin, Scala, Groovy, Clojure ● Studied at ISEL Lisboa in Computer Science and Telecom Engineering ● Spring Professional 2020 ● OCP11 ● Kong Champion

Slide 3

Slide 3 text

Variances The ability to establish hierarchies between complex types. Example: is a list of credit cards the same as a list of cards and vice-versa? Sounds logic that a list of credit cards is also a list of cards, but is it?

Slide 4

Slide 4 text

Covariance ● Easy to understand ● Intuitive ● Restrictive

Slide 5

Slide 5 text

Covariance abstract class DrinksService { protected val database by lazy { HashMap() } fun sendDrink(drink: DRINK) = run { database[UUID.randomUUID()] = drink } abstract fun getBox(): BOX } open class Box open class CardboardBox : Box() open class PlasticBox : Box() DrinkService is covariant to Box!

Slide 6

Slide 6 text

Covariance val coldDrinksBoxService: DrinksService = object: DrinksService() { override fun getBox(): FamilyBox { TODO("Not yet implemented") } } DrinkService is covariant to Box! Will this compile? Yes! Because of covariance DrinksService Is seen as a subclass of: DrinksService 👍

Slide 7

Slide 7 text

Covariance val coldDrinksFamilyBoxService: DrinksService = object: DrinksService() { override fun getBox(): Box { TODO("Not yet implemented") } } DrinkService is covariant to Box! Will this compile? No! Because of covariance DrinksService Is NOT seen as a subclass of: DrinksService 👎

Slide 8

Slide 8 text

Contravariance ● Hard to understand ● Counter intuitive ● Restrictive

Slide 9

Slide 9 text

Covariance abstract class DrinksService { protected val database by lazy { HashMap() } fun sendDrink(drink: DRINK) = run { database[UUID.randomUUID()] = drink } abstract fun getBox(): BOX } open class Drink open class WarmDrink : Drink() open class ColdDrink : Drink() DrinkService is contravariant to Drink!

Slide 10

Slide 10 text

Contravariance val drinksFamilyBoxService: DrinksService = object : DrinksService() { override fun getBox(): FamilyBox { TODO("Not yet implemented") } } DrinkService is contravariant to Drink! Will this compile? Yes! Because of contravariance DrinksService Is seen as a subclass of: DrinksService 👍

Slide 11

Slide 11 text

Covariance val coldDrinksFamilyBoxService: DrinksService = object : DrinksService() { override fun getBox(): FamilyBox { TODO("Not yet implemented") } } DrinkService is contravariant to Drink! Will this compile? No! Because of contravariance DrinksService Is not seen as a subclass of: DrinksService 👎

Slide 12

Slide 12 text

Contravariance can be very counterintuitive to understand but essentially in common words, it means that the combination with a certain complex type will still result in a composed generic type in this case a DrinksService. The idea is that the resulting composed type will have its own hierarchy and that can move along or against the original hierarchy of its individual contained types. And so Drinks service is covariant to BOX, but contravariant to DRINK. Therefore naturally if covariant, then the type makes only sense to use as an output and thus the modifier out. In the same if contravariant, then it only make sense to use that generic type as input and thus in.

Slide 13

Slide 13 text

In Java ● Same implementation ● Same rules ● A bit more code

Slide 14

Slide 14 text

In Java - The Drinks Service public class DrinksServiceJava { private final Map database = new HashMap<>(); public void sendDrink(DRINK drink) { database.put(UUID.randomUUID(), drink); } @SuppressWarnings("unused") public BOX getBox(Function drinks) { return drinks.apply(database.remove(database.keySet().stream().findFirst().orElseThrow())); } }

Slide 15

Slide 15 text

In Java - Service initialization DrinksServiceJava drinksFamilyBoxService = new DrinksServiceJava(); DrinkService is contravariant to Drink! DrinkService is covariant to Box! Different Language Different Syntax The same stuff

Slide 16

Slide 16 text

Resources ● https://kotlinlang.org ● https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.re flect/-k-type-projection/ https://www.youtube.com/watch?v=D50Cluc2Vp4

Slide 17

Slide 17 text

Resources ● Source Repository ○ https://github.com/jesperancinha/asnsei-the-right-waf ● Location Directory: ○ https://github.com/jesperancinha/asnsei-the-right-waf/tree/main/demo-projects/drinks-manager Use git clone from the command prompt to download the full code base: > git clone https://github.com/jesperancinha/asnsei-the-right-waf.git You’ll be prompted for a username and password which should be your github account. > cd /demo-projects/drinks-manager The easy way: > make b > make run The manual way: > gradle build > ./gradlew run

Slide 18

Slide 18 text

About me ● Homepage - https://joaofilipesabinoesperancinha.nl ● LinkedIn - https://www.linkedin.com/in/joaoesperancinha/ ● YouTube - JESPROTECH ■ https://www.youtube.com/channel/UCzS_JK7QsZ7ZH-zTc5kBX_g ■ https://www.youtube.com/@jesprotech ● Bluesky - https://bsky.app/profile/jesperancinha.bsky.social ● Mastodon - https://masto.ai/@jesperancinha ● GitHub - https://github.com/jesperancinha ● Hackernoon - https://hackernoon.com/u/jesperancinha ● DevTO - https://dev.to/jofisaes ● Medium - https://medium.com/@jofisaes

Slide 19

Slide 19 text

Questions?

Slide 20

Slide 20 text

Thank you!