Type parameter allows us to define methods or classes in terms of type that will be specified later. It’s like creating a placeholder for the type, which we can configure and define. Type parameterization allows you to write generic classes and methods. For example In Java List<T> can be defined as List<String>, List<Integer>, List<Double>, etc. Similarly in scala or any other language we can define it.
To understand type system, we need to understand Variance and Bounds
Type variance is a generic type concept, and defines the rules by which parameterized types can be passed into methods. Variance can be defined in Covariant, Invariant and Contravariant. Below is the table which describes the variance types.
Symbols Name Description Array[T] Invariant Used when elements in the container are mutable. Example: Can only pass Array[String] to a method expecting Array[String] . Seq[+A] Covariant Used when elements in the container are immutable. This makes the container more flexible.Example: Can pass a Seq[String] to a method expected Seq[Any] . Foo[-A] Contravariant Contravariance is essentially the opposite of covariance, and is rarely used.
The following examples, showing what code will and won’t compile with the Grandparent, Parent, and Child classes, can also be a helpful reference to understanding variance.
Note: Credit to Alvin Alexander for the below example.
https://gist.github.com/kishorenayar/f54b18eaadde525a1838