I think the example is right. Cat is a subtype of Animal, and Animal is a subtype of Thing
Cat < Animal < Thing
So if the function takes any animal, of course it can take a cat (so its covariant in argument). And because all animals are things, we can say the output type of f is Thing.. its just less accurate than Animal but still correct - that is the contravariance in the result.
Cat extends Animal means "Cat can do everything Animal can, plus maybe more stuff". So all cats are animals, but not all animals are cats. So Cat is a subtype of Animal.
For the second question,
"an instance of subclass can replace an instance of superclass" is the right one.
Really it makes a lot of sense intuitively. e.g say Int is a subclass of Number (a simpler way to read is just "Int is a Number") . then anything you can do with numbers, you can do with ints too so we can put an int in place of a number.
My first question is about terminology used. I get why the code example works, but the description I quoted says the reverse (i.e. "Animal is a subtype of Cat", and "Animal is a supertype of Thing"). I assume that it's an error then.
Thx for the answer to the second question :). I think my mind put an additional "by" in that sentence and got confused.
> I ask because I'm not sure about the grammar aspect, and in my native language (Polish) we have a few ambiguities like that, which I sometimes jokingly write down with an arrow, e.g. "A can be ---substitutes for--> B" or "A can be <--substituted for-- B", to make it damn explicit which direction the word works.
-------------------------
I think it's confusing for 2 reasons: passive voice and prepositions.
1) Passive voice - instead of saying A substitutes for B (active voice) it says A can be substituted for B (passive voice.)
2) Prepositions - "be substituted" can collocate with "for" or "by" with the opposite meaning!
A <-- can be substituted by <-- B (use B where you would expect A)
A --> can be substituted for --> B (use A where you would expect B)
Yes I think he has made a mistake there. He did get it right earlier in the article he says "This makes Cat a subtype of Animal. That means that all Cats are Animals, but not all Animals are Cats."
The example is actually wrong. Functions are contravariant on their input and covariant on their output.
The basic premise behind subtypes is that an object of a subtype can be used anywhere that an object of its supertype can be used. Just as an example, if you replace f1 : Animal -> Animal with f2 : Cat -> Thing, there might be some animals that aren't cats, so f2 can't replace f1 everywhere. This is the reason that functions are contravariant on their input.
Cat < Animal < Thing
So if the function takes any animal, of course it can take a cat (so its covariant in argument). And because all animals are things, we can say the output type of f is Thing.. its just less accurate than Animal but still correct - that is the contravariance in the result.
Cat extends Animal means "Cat can do everything Animal can, plus maybe more stuff". So all cats are animals, but not all animals are cats. So Cat is a subtype of Animal.
For the second question,
"an instance of subclass can replace an instance of superclass" is the right one.
Really it makes a lot of sense intuitively. e.g say Int is a subclass of Number (a simpler way to read is just "Int is a Number") . then anything you can do with numbers, you can do with ints too so we can put an int in place of a number.