Scala | Variances
Variance is the interconnection of Sub-Typing relationships which are either of complicated types or of their constituent types. Variance explains inheritance correlation of Types that have parameters or arguments within them. These types belong to the generic classes, which takes a type as a parameter. In the presence of Variance, one can create relations between complicated types and in its absence, we won’t be able to reiterate the abstraction class. The Scala Variances are of three types, which are as follows:
Covariant
Contravariant
Invariant
Let's play with them together to make it easier.
3. Variance ?
“Variance refers to how subtyping between complex types relates to subtyping
between their components”
Other words, we can also say
“Variance is the correlation of subtyping relations of complex type and
subtyping relations of their component type”
5. Liskov Substitution Principle ?
If S is a subtype of T, then objects of type T may be replaced with objects of
type S without altering any of the desirable properties of the program. [Wiki]
That means that objects of a superclass shall be replaceable with objects of its
subclasses without breaking the application. That requires the objects of your
subclasses to behave in the same way as the objects of your superclass.
6. Applying LSP to Variance
Earlier :-
“Variance is the correlation of subtyping relations of complex type and
subtyping relations of their component type”
After :-
Variance is the correlation of when we can substitute complex type and when
we can substitute their component type.
7. Variance Check?
class Container[+A] // A covariant class
class Container[-A] // A contravariant class
class Container[A] // An invariant class
Scala compiler will check that there are no problematic combinations when
compiling a class with variance annotation.
In general, we can say it check the following
● Covariant type parameters can only appear in method results.
● Contravariant type parameters can only appear in method parameters.
● Invariant type parameter can appear anywhere.
8. Covariant?
If “S” is subtype of “T” then Container[S] is a subtype of Container[T].
To represent Covariance relationship between two Parameterized Types, Scala uses
the following syntax:
Prefixing Type Parameter with “+” symbol defines Covariance in Scala.
10. Contravariant?
If “S” is subtype of “T” then Container[T] is is a subtype of Container[S].
To represent Contravariant relationship between two Parameterized Types, Scala
uses the following syntax:
Prefixing Type Parameter with “-” symbol defines Contravariant in Scala.
12. Invariant?
If “S” is subtype of “T” then Container[S] and Container[T] don’t have
Inheritance Relationship or Sub-Typing. That means both are unrelated.
In Scala, by default Generic Types have In-Variant relationship. If we define
Parameterized Types without using “+’ or “-” symbols, then they are known as
Invariants.