Transcript for:
Generic Variance in Kotlin

I've been busy writing chapter 19 of cotlin and Illustrated guide and this chapter is going to cover generic variance in cotlin so in other words explaining why an array of integers is not a subtype of array of numbers and I think one thing that's often overlooked is that variance doesn't only apply to generics it actually applies to regular type hierarchies as well in fact I think that by understanding how variance applies with just normal type inheritance and type hierarchies we'll get a better understanding of why variance applies to generics as well so let's jump in in most cases a type contains one or more associations to other types and to show you what I mean I've got here an interface called vending machine and it Associates with two other types so it's got a parameter type here which is coin and it's got a return type here which is snack so in other words you it's a vending machine you put in a coin and you get a snack back variance describes the nature of the relationship between between the container type and one of those associations that it contains so for this interface variants can describe the relationship between the vending machine and this parameter type or it can explain the relationship between the vending machine and this return type so if we were to create a class that implements this interface we could just keep these Associated types exactly the same as they are in this interface and I think most of the time that's actually probably what we do so in other words if we create a subtype the parameter type would still be coin and the return type would still be snack just like they are in this interface but it doesn't have to be this way these Associated types can climb up or down their type hierarchies depending on where they are in this container class as long as we uphold the contract which is that this purchase function must always accept a coin and return a snack so in other words as long as the subass or the subtypes of vending machine still accept anything that's a coin and return something that's a snack everything's good to demonstrate this let's start with the return type which is snack let's assume we have a type hierarchy that looks something like this where the snack. random function can return either a candy bar or a bag of Trail Mix so if this subtype simple vending machine if it were to always return a candy bar would this function still be returning a snack and it would because candy bar is a kind of snack uh so instead of snack. random right here we could just instantiate a candy bar directly and we can also change this return type to candy bar so in other words just like simple vending machine is a subtype of vending machine candy bar is also a subtype of snack so as this container type becomes more specific so can this return type and and since they become more specific together we call this co-variance where the prefix Co means together now I've only got one function in this example but covariance applies to the return type of every function and also to properties that are declared with the vow keyword now this doesn't work the other way so we can't replace it with a type that's more General so let's say That Snack derives from another type called Product and product includes both snacks and toys in that case we can't declare that this Returns the product type and why is that that's because the contract said that the vending machine will accept a coin and return a snack and if it returns toys instead of snacks some poor kid is going to end up breaking his teeth trying to chew an action figure or something so cotlin prevents us from doing that and it gives us this compiler error instead so let's put this back so to summarize before we move on the relationship between a container type and one of its uh return types is called covariant because as the container type becomes more specific so can the return type now what about the parameter type here can it also become more specific in subtypes of vending machine well the contract says that this function must accept any kind of coin and return some kind of snack so if we were to declare a more specific type here like a quarter then it would break its contract now sure a quarter is a kind of a coin but um it has to accept any kind of coin including dimes and so if we declared that it only accepts quarters the people who have dimes wouldn't be able to get their snack so it would not be type safe to allow that here and what about a more General type what if this machine could accept any kind of money including either a coin or a bill since this money type still includes all coins it'd be perfectly type safe to allow this now in cotlin we can try to do this but we'll get a compiler error saying that this function doesn't override anything so even though it'd be type safe to allow a more General type here cotlin is not going to allow it and the reason for that is that cotlin supports function overloading so in other words we can remove this override keyword here and that would make this function an overload rather than an override and that would fix this error we would still have to implement the missing function though in which case we would be juggling two function bodies and that's not exactly what we want so just to reiterate from a type system perspective it's totally fine to allow a parameter to have a more General type in the the subtype of the container it's just that we can't do that in Colin because of function overloading but you know you can't overload is properties with a function type so let's change our interface from having a function to having a property with a function type and in our class we can just change this to a property with a Lambda and now we can change this coin type to something more General like money and as we can see it compiles just fine so simple vending machine is a subtype of vending machine but but money is a super type of coin so in other words as the container type becomes more specific this parameter type can become more General since they become more specific in opposite directions we call this Contra variance we only have one type parameter in this example but again this holds true for all parameters in the container type so we can summarize our findings like this within a subtype return types can become more specific which is known as co-variance and parameter types can become more general which is contravariance and now that we've seen variance apart from generics it makes a whole lot more sense why generic variance works the way that it does so let's take a look at this vending machine interface uh where I've converted it into a generic when a type parameter is declared without it can only publicly appear as a return type which as we've seen means that the container type can have a covariant relationship with it and when a type parameter is declared with a keyword in then it can only publicly appear as a function parameter which also as we've seen means that the container type can have a contravariant relationship with it so given two parameterized types we can look at their type arguments and as long as the one whose type parameter is marked as out is the same or more specific than the first and as long as the one who typed parameter is marked within is the same or more General than the first then the contract isn't broken and it's perfectly typ safe for the second to be a subtype of the first and there you have it variance without generics can help clarify why variance works with generics good job working your way through all of the content in this video as I said earlier you'll be able to read a lot more about this when chapter 19 of cotlin and Illustrated guide comes out in the meantime keep experimenting with this stuff keep coding and of course feel free to reach out to me in the comments section or on social media with any thoughts ideas or questions you've got see you next time you've read the chapters online and now I'm proud to present the lean puff edition of cotlin and Illustrated guide take the book offline with you mark it up in your favorite PDF software and get early access to new chapters as they're written you can pick up your copy today just go to book. typ elias.