I want to start by saying that I know this topic has been discussed in depth on Stack Overflow. But I don't feel like the explanations given provide a strong story that helps to retain the examples and knowledge.
Can someone provide a metaphor or story to help me understand the concept of covariance and contravariance in relation to the following example in Kotlin?
Here are the constructs:
open class Animal
class Dog : Animal()
fun doSomething(fn: (Dog) -> Number) {}
I'm trying to understand why the following code works:
animalToIntMethod: (Animal) -> Int = {TODO()}
doSomething(animalToIntMethod)
In Kotlin, the internal representation of (Dog) -> Number is Function<Dog, Number>, which involves the use of contravariance and covariance, specifically Function<in T, out R>. However, I'm having trouble understanding how these concepts actually work. Could someone please explain the principles of contravariance and covariance in this context?
It is hard to explain the whole concept in a few words and as you said, you already read some explanations, so I think I would pretty much repeat what was said in other places. Instead, I'll focus on your example.
Your function
doSomething()requires another function which "converts" a dog into a number:(Dog) -> Number. Let's saydoSomething()is a documentalist who creates some kind of a catalogue of dogs. This person has to know the height of each dog to put it into the catalogue, but they don't know how to measure the height of a dog, so they need a qualified veterinarian for this. Veterinarian is our(Dog) -> Numberfunction - they know how to provide a height for a given dog.We found a veterinarian
animalToIntMethodwho is super-qualified, they know how to measure any animal in the world - therefore their type is(Animal) -> Int.The area of focus of both persons is different. Documentalist needs someone, who can measure dogs specifically. Veterinarian doesn't focus on dogs, they can measure animals in general, their area of expertise is much wider. But of course, that doesn't mean they can't cooperate. Veterinarian can measure any animal, including dogs.
This is an example of contravariance, represented as
inin theFunction<in T, out R>. Documentalist doesn't need someone working with dogs exclusively (that would be invariance). It is fine if the provided veterinarian can work with mammals or animals in general - as long as they can work with dogs.