Homoscaliens explains covariant to a duck

Homoscaliens: So would you like to know what a covariant is?
Duck: Duck Duck
Homoscaliens: Do you know already what inheritance is right?
Duck: Duck Duck
Homoscaliens: So imagine you have a method which accepts a "Dog", now imagine that method could somehow magically change anything you pass to it as a caller to a dog.  so you pass it a puppy it will then change the orig reference you had to that puppy to a dog.  that wouldn't be too good right?
Duck: Duck Duck
Homoscaliens: it wouldn't really be a good idea because then you can call your orig puppy like puppy.puppyMe() however as it has changed fully to point to a dog it has no idea that puppeMe() method is not valid anymore, got it?
Duck: Duck Duck
Homoscaliens: However we don't have really that problem because we do not change such things we have no real way.
Duck: Duck Duck
Homoscaliens: But if you had such a way it would be a problem.
Duck: Duck Duck
Homoscaliens: In arrays you can do that! a problem!
Duck: Duck Duck
Homoscaliens: So if your method accepts an argument of type ArrayBuffer[Dog] and you actually pass as an argument instead of ArrayBuffer[Dog] ArrayBuffer[Puppy] I can traverse your array and update it to an array of Dogs instead! now you will try on your side to call puppeMe() and it won't work!
Duck: Duck Duck
Homoscaliens: that means its not a good idea to allow this.
Duck: Duck Duck
Homoscaliens: so it is not allowed! as if you defined ArrayBuffer[Dog] you cannot pass ArrayBuffer[Puppy] its invariant! only ArrayBuffer[Dog] as its mutable!
Duck: Duck Duck
Homoscaliens: however if your container is immutable you can do that! in that case it can accept arrays of subtypes, example Seq[Dog] and you can pass it Seq[Puppy] this works because Seq is Seq[+A] while ArrayBuffer is ArrayBuffer[A]


if you didn't like this then just read this:
http://stackoverflow.com/questions/663254/scala-covariance-contravariance-question/674090#674090

Comments