Scala: Generic classes and Variance

Generic classes are classes which take a type as a parameter. This means, one class can be used with different types without actually writing down it multiple times. They are particularly useful for collection classes.

Defining a generic class:

Generic classes take a type as a parameter within square brackets [ ]. One convention is to use the letter A as type parameter identifier, though any parameter name may be used. Let us understand this with the help of an example. As I have already described that generic classes are useful for collection classes, So let’s try to understand the Stack collection.

This implementation of a MyStack class takes type A as a parameter. This simply means the parameter elems can only store elements of type A. The method push only accepts objects of type A.

Now as we understood how to define the generic classes, let’s understand how to use them.

Usage:

To use a generic class, put the type in the square brackets in place of A.

Here, the stack can only take Ints. However, if the type argument had subtypes, those could be passed in:

Here, class Cat and Dog both extends Animal so we can push instances cat and dog onto the stack of Animal.

Variance:

Variance defines Inheritance relationships of Parameterized Types. Variance is all about Sub-Typing. Variance makes Scala collections more Type-Safe.
Types of Variance:
1. Covariant
2. Invariant
3. Contravariant

Covariant:

If S is a subtype of T, then List[S] is a subtype of List[T].
scala-covariant

In Scala, Syntax to represent covariant relationship between two parametrized types is prefixing Type Parameter with “+” symbol. Let’s understand covariance with the help of an example:

As we can see above, class Puppy is a subtype of Dog and we are able to define the dogCarer and puppyCarer both but if we remove the “+” sign we get a compile-time error.

Contravariant:

If S is a subtype of T, then List[T] is a subtype of List[S].

scala-contravariance

In Scala, Syntax to represent contravariant relationship between two parametrized types is prefixing Type Parameter with “-” symbol. Let’s understand contravariance with the help of an example:

As we can see above, class SuperType is a subtype of Type[AnyVal] and class SubType is a subtype of Type[Int]. We can see typeCarer object is able to display both SuperType and SubType but if we remove the “-” sign we get a compile-time error.

Invariant:

If S is a subtype of T then List[S] and List[T] don’t have Inheritance Relationship or Sub-Typing. That means both are unrelated.
In Scala, by default Generic Types have Non-Variant relationship. If we define Parameterized Types without using “+” or “” symbols, then they are known as Invariants. Let’s understand contravariance with the help of an example:

As we can see above, class Cat and Dog are subtypes of Animal. So catContainer compiles fine whearas animalContainer throws compile time error saying Container of type Animal cannot hold Container of type Cat.

Check out my Github repo for complete scala tutorial

Conclusion:

To sum up this blog, we concluded the following:

  • Generic classes are classes which take a type as a parameter i.e., one class can be used with different types without actually writing down it multiple times.
  • Variance defines Inheritance relationships of Parameterized Types.
  • Various types of variance are: Invariant, Covariant and Contravariant.
  • Invariant: If S is a subtype of T then List[S] and List[T] don’t have Inheritance Relationship or Sub-Typing.
  • Covariant: If S is a subtype of T, then List[S] is a subtype of List[T].
  • Contravariant: If S is a subtype of T, then List[T] is a subtype of List[S].

References:

  1. Scala Documentation
  2. Journal Dev

Knoldus-blog-footer-image

Written by 

Ayush is a Software Consultant having more than 11 months of experience. He has knowledge of various programming languages like C, C++, Java, Scala, JavaScript and is currently working on Big Data Technologies like Spark, Kafka, ElasticSearch. He is always eager to learn new and advance concepts in order to expand his horizon and apply them in project development with his existing knowledge. His hobbies includes playing Cricket, Travelling, Watching Movies

Leave a Reply

Knoldus Pune Careers - Hiring Freshers

Get a head start on your career at Knoldus. Join us!