Open In App

Scala – Covariance

Improve
Improve
Like Article
Like
Save
Share
Report

Variance is the interconnection of Sub-Typing relationships which are either of complicated types or of their constituent types. Scala provides three types of variance:

  • Covariant
  • Contravariant
  • Invariant

Covariance states that if there are two parameterized types such that S is a subtype of T, then List[S] is a subtype of List[T]. This is an inheritance relationship. So, this basically defines the relationship whether we can replace a type by its base type. Simply putting in words, if we take an example where Car is a subtype of Vehicle, then List[Car] is a subtype of List[Vehicle]. Therefore, we can replace List[Car] by List[Vehicle]. When we declare a type to be covariant, then its safe use at various positions becomes limited. In the case of immutable types, covariance is widely used.
Syntax:

List[+T]

Here, T is a type parameter and the “+” symbol represents Scala covariance.

Let us discuss this concept with the help of examples:
Example 1:




// Scala program to illustrate the concept of covariance
  
// Creating an abstract class 
// for Flower 
abstract class Flower 
{
    def name: String
}
  
// Creating a sub-class Lily 
// of Flower 
case class Lily(name: String) extends Flower
  
// Creating a sub-class Carnation
// of Flower 
case class Carnation(name: String) extends Flower 
object Covariance extends App
{
      
    // Creating a method
    def FlowerNames(flowers: List[Flower]): Unit =
    {   
        flowers.foreach 
        {
            flower => println(flower.name)
        }
    }
      
    // Assigning names
    val lily: List[Lily] = List(Lily("White Lily"), 
                                Lily("Jersey Lily"))
    val carnations: List[Carnation] = List(Carnation("White carnations"),
                                           Carnation("Pink carnations"))
  
    // Print: names of lily 
    FlowerNames(lily)
  
    // Print: names of carnation 
    FlowerNames(carnations)
}


Output:

White Lily
Jersey Lily
White carnations
Pink carnations

Explanation: In the above example, Lily and Carnation are subtypes of Flower. So, it is evident that a List[Lily] is a List[Flower] and a List[Carnation] is also a List[Flower], and we can substitute any of them for a List[Flower]. In the later part of the code, there is a method FlowerNames that prints names of flowers and the acceptable argument is a list of flowers. If the two lists are covariant, only then the method calls will compile and the flower names will get printed respectively. So, as Lily and Carnation are a subtype of Flowers and the last two lines will execute due to covariance.
Note:

  • Abstract class is utilized here to apply covariance as it has List[+T] with it where the type parameter T is covariant.
  • A trait App is used here to speedily change objects into workable programs.

Example 2:




// Scala program to illustrate the concept of covariance
  
// Creating an abstract class 
// for Animal
abstract class Animal 
{
    def name: String
}
  
// Creating a sub-class Mammal
// of Animal 
case class Mammal(name: String) extends Animal
  
// Creating a sub-class Reptile
// of Animal 
case class Reptile(name: String) extends Animal 
  
object CovarianceExample extends App
{
      
    // Creating a method
    def SpecieNames(animals: List[Animal]): Unit =
    {   
        animals.foreach 
        
            animal =>println(animal.name)
        }
    }
      
    // Assigning names
    val mammals: List[Mammal] = List(Mammal("Zebra"), 
                                     Mammal("Horse"))
    val reptiles: List[Reptile] = List(Reptile("Snake"), 
                                       Reptile("Lizard"))
  
    // Print: names of mammals
    SpecieNames(mammals)
  
    // Print : names of reptiles
    SpecieNames(reptiles)
}


Output:

Zebra
Horse
Snake
Lizard


Last Updated : 03 Jul, 2020
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads