I have a confusion in understanding covariance type being restricted in method parameters. I read through many materials and I am unable to get them the below concept.
class SomeThing[+T] {
def method(a:T) = {...} <-- produces error
}
In the above piece of code, a is of type T. Why can we not pass subtypes of T? All the expectations of method on parameter x, can be fulfilled by subtype of T perfectly.
Similarly when we have contravariant type T (-T), it can not be passed as method argument; but it is allowed. Why I think it can not be passed is: for e.g, say method invokes a method (present in object a) on a which is present in T. When we pass super type of T, it may NOT be present. But it is allowed by compiler. This confuses me.
class SomeThing[-T] {
def method(a:T) = {...} <-- allowed
}
So by looking at the above, it is covariant that should be allowed in method arguments as well as in the return type. Contravariant can not be applied.
Can someone please help me to understand.
The key thing about variance is that it affects how the class looks from the outside.
Covariance says that an instance of
SomeThing[Int]can be treated as an instance ofSomeThing[AnyVal]becauseAnyValis a superclass ofInt.In this case your method
would become
This is clearly a problem because you can now pass a
Doubleto a method ofSomeThing[Int]that should only acceptIntvalues. Remember that the actual object does not change, only the way that it is perceived by the type system.Contravariance says that
SomeThing[AnyVal]can be treated asSomeThing[Int]sobecomes
This is OK because you can always pass an
IntwhereAnyValis required.If you follow through the logic for return types you will see that it works the other way round. It is OK to return covariant types because they can always be treated as being of the superclass type. You can't return contravariant types because the return type might be a subtype of the actual type, which cannot be guaranteed.