Connecting...

W1siziisimnvbxbpbgvkx3rozw1lx2fzc2v0cy9zawduawz5lxrly2hub2xvz3kvanbnl2jhbm5lci1kzwzhdwx0lmpwzyjdxq

Scala: Generic classes and Variance by Ayush Hooda

W1siziisijiwmtkvmdqvmjmvmtavmjkvmdavodyzl3blegvscy1wag90by0xmtexmzezlmpwzwcixsxbinailcj0ahvtyiisijkwmhg5mdbcdtawm2uixv0

How do you define and use generic classes? What is variance?

All these questions are answered for us by Software Consultant, Ayush Hooda. Find out exactly what they do and what they mean for your programming. 

 

'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 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].

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].

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].'
 
This article was written by Ayush Hooda and originally posted on Knoldus blog.