
Introduction to Scala Generics
Scala Generics are kind of like functions for variable types. With the usage of Scala Generics you should reuse our code. Normally, make a function for a task that we do a lot of, so instead of having to repeat the same code over and over again, we let the compiler and computer do that behind the scenes for us. Scala Generics do the same thing, except for data structures.
Let’s say we want to make a linked list of integers. Then later you want to make a linked list of strings. when you make a generic type, you tell the compiler “this is how you make a linked list”, then when you want a linked list of integers, you tell the compiler “make me a linked list of integers”, then when you want a linked list of strings, you tell the compiler “make me a linked list of strings,” and it does all the work while you get on with your life, with probably more coding.
Most Important points to Remember :
- The symbol used for a type parameter of a simple type is A, like List[A].
- The symbols used for a type parameter of second, third, fourth, and so on, types in generic classes are respectively B, C, D, and so on.
- The symbol used for a key is A and for a value is B in Scala Map.
- The symbol used for a numeric value is N.
Defining a Scala generics class
In other words scala generic class means that the items or functions in that class can be generalized with the parameter(example T) to specify that we can add any type as a parameter in place of T like Integer, Character, String, Double or any other user-defined type.
Declaring a generic method is very similar to declaring a generic class. We still put type parameters in square brackets.
And, the return type of the method can also be parameterized type:
class GenericStack[A](elems: List[A]) {
def isEmpty: Boolean = elems.isEmpty
def push(elem: A): List[A] = {
elem :: elems
}
def pop: List[A] = {
if(!isEmpty) {
elems.tail
}
else {
throw new NoSuchElementException("pop of an empty stack")
}
}
}
Type Bounds in Scala
In Scala, Type Bounds are restrictions on Type Parameters or Type Variable. By using Type Bounds, we can define the limits of a Type Variable. Scala Type Bounds give us the benefit of Type-Safe Application Development.
Scala supports the following Type Bounds for Type Variables:
- Scala Upper Bounds
- Scala Lower Bounds
Upper Type Bounds
The easier type bound to understand is upper type bound ‘<:’. This indicator would be the same as ‘:’ when we create a value and we give it a specific type.
class Parking[A <: Vehicle]
val a: Parking means that “a” must be an instance of Parking or a subtype of Parking.
In the type scenario, Parking[A <: Vehicle] means that the A
type must be a type or subtype of Vehicle.
Because of that, if we create a Vehicle, Car, Jeep, or Motorcycle Parking, everything works.
The following lines will add to a test and the result would be SUCCESS:
new Parking[Vehicle] shouldBe a[Parking[_]]
new Parking[Car] shouldBe a[Parking[_]]
new Parking[Jeep] shouldBe a[Parking[_]]
new Parking[Motorcycle] shouldBe a[Parking[_]]
Lower Type Bounds
On the other hand, we have the lower type bound, ‘>:’, which indicates the opposite of ‘<:’.
[A >: Vehicle] will restrict A to supertypes of Vehicle, Vehicle included.
Its uses are mainly related with co- and contravariance .
Let’s start by understanding which type of relationship represents a lower type bound. A >: B means that A must be B or a higher from B, B being the frontier (bound).
class Parking[A >: Jeep](val place: A)
In this Parking, we could park any supertype of Jeep, meaning, Car, Vehicle, Thing… AnyRef..
class Parking[A >: Jeep <: Vehicle](val plaza: A)
Conclusion
In this blog, now we know that, with generic classes, we can achieve type-safety while avoiding having to declare a new container class for each type it contains.
Now we also know the difference in declaring both generic and non-generic methods.


