The conclusion is that the paternity of generic covariant is the paternity of identity. After the inversion of generic type, the parent-child relationship is like, which is the relationship of behavior likeness.

General interpretation

When it comes to Generic covariant, the most common explanation is that type A is A subtype of type B, so Generic<A> is also A subtype of Generic<B>. Inversely, Generic<B> is A subtype of Generic<A>.

The first situation is easy to understand, father and son are wearing vests, vests of the father is still (vests of the son) father, in line with intuition. But what about the inversion of the parent-child relationship? I read a lot of articles and started to talk about how covariant out refers to the return type, producer, and contravariant in refers to the consumer, which can only appear at parameter positions.

OK, the truth I understand, but the most let me tangle why the son set a vest to become a father, this question but no one directly answer me.

Start from the family ethics

Here we use a piece of code from Kotlin Core Programming to get a good picture of the father-son relationship.

When writing a Comparator< double >, there is a mutableList. When writing a Comparator< double >, there is a mutableList. When writing a Comparator<Int>, there is a Comparator<Int>. It’s the same algorithm. They are subclasses of “Number”. If you Comparator<Number>, it’s completely OJBK. Now the relationship is dad Number has an older son Double and a younger son Int.

val numberComparator = Comparator<Number>{
	n1, n2 -> n1.toDouble().compareTo(n2.toDouble())
}

val doubleList = mutableListOf(2.0.3.0)
doubleList.sortWith(numberComparator)

val intList = mutableListOf(2.5)
intList.sortWith(numberComparator)
Copy the code

That makes perfect sense. When a Comparator<Number> is accepted, it means that the Comparator<Number> is the son of the Comparator<Double>.

Wait, there’s something wrong, something weird.

It’s normal to be surprised, because when we talk about father-son relationships, we tend to think of them as identity relationships. But this is not the case in contravariant father-child relationships, where two classes behave like father and son but are not in reality.

So when we think of as father and son on behavior, the parent class inclusive (after all, the father loves the boundless), the parameter position we declare for the parent class type, with greater flexibility, because the parent class can undertake it’s have different subclasses, and the subclass has learned of the parent class all skill (inheritance), so it can undertake the work of father can bear, In some cases it is better (type determination, casting subtypes), with the father doing the work and the sons doing the work. When roles change, we assume that the son replaces the father. It looks like a father-son thing, so it’s called father-son behavior. But not necessarily father and son, just like contravariant. So, when this substitution occurs, we call the substituted class the behavioral father, and the class that takes charge the behavioral son.

As in this example, when the Comparator<Number> takes the place of the Comparator<Double> and the Comparator<Int>, it becomes the behavioral son.

<Number> <Number> <Number> <Number> <Number> <Number> <Number> <Number> <Number>

public fun <T> MutableList<T>.sortWith(comparator: Comparator<in T>):Unit{
	if(size > 1) java.util.Collections.sort(this, comparator)
}
Copy the code

Emmmm, they don’t have to look at this code, you can see in the above code that they’re actually converting everything to Double for comparison, that’s a bad example, I’ll change it later. The generic parameters modified by the in keyword can be used in the function argument list. The corresponding variables can be cast in the function body. In indicates that modification is allowed.

Here’s a more convincing example from bennyhuo’s tutorial. Thank you

open class Waste// Unclassified garbage can be put into general garbage canDustbin<Waste"> < p style =" max-width: 100%; clear: both

class DryWaste : Waste(a)// Dry garbage, son of identity

class Dustbin<in T : Waste> {
    fun put(t: T) {
        when(t){
          is Waste -> TODO()
          is DryWaste -> TODO()
          else -> TODO()
        }
    }
}

fun contravariant(a){
    val dustbin: Dustbin<Waste> = Dustbin<Waste>()// Common trash can
    val dryWasteDustbin: Dustbin<DryWaste> = dustbin// The type is declared as the dry garbage can, which is replaced by the general garbage can, which is the son of behavior

    val waste = Waste()
    val dryWaste = DryWaste()

    dustbin.put(waste)
    dustbin.put(dryWaste)// The garbage can be disposed of as unclassified garbage, and can also be disposed of as dry garbage.
    //DryWaste is a subclass of Waste

// drywastedustbin. put(waste) // An error is reported, in which case the put parameter must be DryWaste or its subtype
    dryWasteDustbin.put(dryWaste)
}

Copy the code

As you can see, at the lowest level of function execution, the identity’s parent type parameter (Waste) takes over from the identity’s subtype argument (DryWaste), and Dustbin replaces it at the class level, acting like a son. The DryWaste parameter (dustbin. Put (DryWaste)) is used to execute a method in a class. Once the type judgment is converted, the DryWaste parameter takes on a unique role.

You can say that in the inverse scenario, the father in the identity puts on the vest (generic class) behaves like the son, goes into the house (running into the function of the generic class) takes off the vest, your father is still your father. In the end, dad does the work, himself or his son.

dryWasteDustbin: (Dustbin = Dustbin) (in) (T) (DryWaste) (put) (DryWaste) (T) (DryWaste) (put) (DryWaste) (T) (DryWaste) (put) (DryWaste) (T) (DryWaste) (put) (DryWaste) (put) (DryWaste)

For a more accurate explanation of in and out, I still suggest reading official documents or other big guy’s articles. After all, I am a rookie who has not graduated long.

This article is not a detailed solution to the general type of change, just record the answer to my study of the so-called father-son relationship of doubt, if there is a more accurate view, please kindly comment.

As an aside, if you are really free, you can take a look (maybe not)

This is my third post with the Nuggets. I never had the habit of writing a blog before, because I never had the habit of taking notes when I was a student, and I always got good grades, so I thought it was unnecessary to take notes. Waste a lot of energy when you can just get it. Why write it down? So why did I try blogging again? Well, I admit it was for utilitarian purposes. I resigned from the outsourcing company in December 2020. I only worked in my first job for more than 4 months. Now I am studying off-duty. Really do not want to mix, the university failed to carry out their original goal, equivalent to mix for 4 years. The outsourcing company, the tech climate is not great, and I’m not interested in what it can teach me. As a student majoring in computer science, I usually take exams well, but I have little hands-on experience and no project experience. University course, I spend most time outside is self-study 3 d modeling, and finally found it’s a physical strength live, the process is very boring, only after the final model to knead well have a bit of a sense of achievement, role models do not good-looking, not art strength, want to learn the sketch again, so to my original goal farther the distance, I want to do is animation. Later, I wanted to transform TA. I couldn’t chew all kinds of mathematics in computer graphics. During college, I thought about doing Android open, but I just didn’t like Java, so I couldn’t make up my mind.

After learning py for half a year, I was not satisfied with the poor performance. I reviewed C++ and all kinds of cyber attacks. I also thought the cost performance was not high, so I threw it away. To avoid Java, taught myself to Flutter and Dart for a while, not the way I wanted to feel. Go was catching on around that time, and I would probably be a Go programmer now if I hadn’t been introduced to Rust first. I wandered aimlessly until I encountered Rust, the spur of first and true love, and in spite of the online rendering of its difficulty and the timing of the moment, I devoured it without hesitation. That junior summer vacation, began Rust from entry to give up.

In that circumferent classmate is in for take an examination of grind perhaps look for a job review rush about of time, I resemble the deciduous leaf of water surface general along with sex study to look for a job of not much help of matter. I didn’t know what I wanted to do in the future. I just followed the voice in my heart. At that time, I vaguely felt that I wanted to make an Internet product. So I went to learn Flutter, read introductory books about product managers, read books about economics and psychology, and seemed to have no direction at all. In this way, I finished my college life. When my classmates got offers from big factories, I randomly found an outsourcing company. Because up until then, I still didn’t know what I wanted to do. In early January of ’20, I took a break from my internship to teach myself Android, and then COVID-19. I started with Kotlin and went on to brush up on Java. After graduation, I worked in this company to make Android for cars.

Kotlin helped me find a balance between Kt’s many cool features and language design ideas, which always reminded me of Rust. It enabled me to do Android development without having to endure Java’s lengthy syntax, and I could even learn Vertx to use Kt as the background. The lost time is finally over. Maybe something can be done.

There’s too much water. Stop right there. I would like to thank my parents for their support, especially for their support in spite of their inability to understand and poor family circumstances.