Web designing in a powerful way of just not an only professions. We have tendency to believe the idea that smart looking .

scala-logo

Exploring Generics and Variance in Scala

This blog is part of a 10-part series designed to help readers learn Scala from the ground up. Whether you’re new to Scala or looking to solidify your understanding, this series will guide you through its core concepts step by step.

Generics in Scala are a powerful feature that allows developers to write reusable, type-safe code by abstracting over types. They are commonly used in collections and custom classes to handle different data types while maintaining type safety.

Example: Generic Classes and Traits

Generics enable the creation of classes and traits that can work with any type. Here’s a demonstration:

object GenericStructuresDemo extends App {
  // Generic class definition
  class CustomList[+A] {
    // Adding elements with a type constraint
    def addElement[B >: A](element: B): CustomList[B] = ???
    /**
     * Explanation:
     * - A = Cat
     * - B = Dog, which is a subtype of Animal
     * 
     * When adding a Dog to a list of Cats, the result becomes a list of Animals.
     */
  }

  class KeyValuePair[Key, Value]
  // Using generic classes
  val intList = new CustomList[Int]
  val stringList = new CustomList[String]

  // Generic method inside a companion object
  object CustomList {
    def createEmpty[A]: CustomList[A] = ???
  }
  val emptyIntList = CustomList.createEmpty[Int]
  println("Generic classes and methods initialized.")
}

Variance in Generics

Variance determines how subtyping between parameterized types relates to their type parameters. Scala supports three types of variance:

1. Covariance (+A)

A class is covariant if Container[SubType] is considered a subtype of Container[SuperType].

class Animal
class Cat extends Animal
class Dog extends Animal
class CovariantContainer[+A]
val animalContainer: CovariantContainer[Animal] = new CovariantContainer[Cat]

2. Invariance (A)

An invariant class does not allow subtyping between parameterized types.

class InvariantContainer[A]
val invariantAnimalContainer: InvariantContainer[Animal] = new InvariantContainer[Animal]
// val invariantAnimalContainer: InvariantContainer[Animal] = new InvariantContainer[Cat] // This won't compile

3. Contravariance (-A)

A class is contravariant if Trainer[SuperType] is a subtype of Trainer[SubType].

class Trainer[-A]
val animalTrainer: Trainer[Cat] = new Trainer[Animal]

Bounded Types in Generics

Bounded types restrict the types that can be used as type parameters.

1. Upper Bound (<:)

Restricts the type parameter to be a subtype of a specific type.

class Enclosure[A <: Animal](animal: A)
val dogCage = new Enclosure(new Dog)
// val carCage = new Enclosure(new Car) // Compilation error: Car is not a subtype of Animal

2. Lower Bound (>:)

Restricts the type parameter to be a supertype of a specific type.

class Enclosure[A >: Dog](animal: A)
// Accepts Dog, Animal, or any supertype of Dog

Summary of Key Concepts

  • Generic Classes: Enable flexible, reusable designs.
  • Variance: Defines the subtyping relationship between parameterized types.
    • Covariance: + enables subtyping.
    • Invariance: No subtyping.
    • Contravariance: allows reverse subtyping.
  • Bounded Types: Restrict types to specific hierarchies using A <: B or A >: B.

By utilizing generics effectively, you can write more abstract and type-safe Scala programs that adapt to different use cases seamlessly.

 

Pizenith is a trusted technology partner specializing in Data Engineering, Machine Learning, AI, Cloud Engineering, DevOps, and Functional Programming with Scala and Java. We help businesses scale with secure, automated, and data-driven solutions, delivering innovation in Test Automation and DevSecOps. Trusted by global enterprises, we empower organizations to stay ahead with AI-powered insights and scalable cloud infrastructure.

Want to future-proof your tech stack? Let’s talk! or reach us at info@pizenith.com.

Write a comment

Your email address will not be published. Required fields are marked *