Scala Generics
Take your programming skills to the next level with interactive lessons and real-world projects.
Explore Coddy →Generics in Scala provide a way to write flexible, reusable code that works with different types. They allow you to create classes, traits, and methods that operate on a variety of data types while maintaining type safety.
Basic Syntax
To define a generic class or trait in Scala, use square brackets after the name:
class Box[T](var content: T) {
def getContent: T = content
def setContent(newContent: T): Unit = { content = newContent }
}
In this example, T is a type parameter that can be replaced with any concrete type when using the class.
Using Generic Classes
To use a generic class, specify the concrete type when creating an instance:
val intBox = new Box[Int](42)
val stringBox = new Box[String]("Hello, Scala!")
println(intBox.getContent) // Output: 42
println(stringBox.getContent) // Output: Hello, Scala!
Generic Methods
Methods can also be generic, allowing them to work with different types:
def printPair[A, B](a: A, b: B): Unit = {
println(s"First: $a, Second: $b")
}
printPair(42, "Scala") // Output: First: 42, Second: Scala
printPair("Hello", true) // Output: First: Hello, Second: true
Type Bounds
Scala allows you to specify upper and lower bounds for type parameters:
- Upper bound:
[T <: UpperType]- T must be a subtype of UpperType - Lower bound:
[T >: LowerType]- T must be a supertype of LowerType
class Animal
class Dog extends Animal
class Puppy extends Dog
def printAnimal[T <: Animal](animal: T): Unit = {
println(s"Animal: $animal")
}
printAnimal(new Dog()) // Works
printAnimal(new Puppy()) // Works
// printAnimal("Not an animal") // Compilation error
Variance
Scala supports variance annotations for generic types:
- Covariance:
[+T]- If A is a subtype of B, then Box[A] is a subtype of Box[B] - Contravariance:
[-T]- If A is a subtype of B, then Box[B] is a subtype of Box[A] - Invariance:
[T](default) - No subtype relationship between Box[A] and Box[B]
For more details on variance, check out the Scala Variance guide.
Best Practices
- Use generics to create reusable code that works with multiple types
- Apply type bounds to restrict the types that can be used with your generic classes or methods
- Consider variance annotations when designing class hierarchies with generic types
- Use Scala Type Inference to reduce boilerplate code when working with generics
Generics are a powerful feature in Scala that enables you to write more flexible and maintainable code. They work seamlessly with other Scala features like Pattern Matching and Higher-Order Functions, making them an essential tool in your Scala programming toolkit.