Contra-Variance is exactly the opposite of covariance. Contra-Variance creates a similar subtyping relation between class and type parameter. So, contra-variance states that if there are two parameterized types such that S is a subtype of T, then List[T] is a subtype of List[S]. We can make a generic class contra-variant by using notation [-S]. We can use contra-variance whenever the type (generic) parameter “consumes” type S or types that accept. We can also use contra-variant as a method argument type, but not as a method return type because it will generate a compilation error.
Here, T is the type parameter and – is the symbol of Contravariance.
Example 1: Let’s consider an example where a Printer[S] is a class that prints some type S. We will define here subclasses for a type:
Lily's name is: White Lily The flower's name is: White Lily
Explanation: Here in this code, if a Printer[Lily] can print any Lily and a Printer[Flower] can print a Flower, then a Printer[Flower] can also print Lily. But the inverse can’t be done as the Printer[Lily] doesn’t know how to print any Flower. So, we can use Print[Flower] as an alternative for Printer[Lily] and we can do so by making Printer[S] Contra-Variant.
Example 2: Consider this example generic class vehicle:
Bike's name is: Yamaha Fazer The vehicle's name is: Yamaha Fazer
Explanation: In this example, we get the same output for both due to contra-variance. As abstract class Get_vehicle_name is contra-variant, we can replace Get_vehicle_name[Vehicle] for Get_vehicle_name[Bike], but inverse is not allowed.