Skip to content
AgileLogics
5 min read

Generics

Prerequisites: Traits

Generics let classes and methods work with any type, while keeping full type checking. You've already used them: List[Int], Option[String], Map[String, Int].

Generic methods

def firstOrElse[A](items: List[A], default: A): A =
  items.headOption.getOrElse(default)

def pairUp[A, B](as: List[A], bs: List[B]): List[(A, B)] = as.zip(bs)

@main def genericMethods(): Unit =
  println(firstOrElse(List(3, 4), 0))
  println(firstOrElse(List.empty[String], "none"))
  println(pairUp(List("a", "b"), List(1, 2)))
3
none
List((a,1), (b,2))

[A] declares a type parameter. The compiler infers A from the arguments: Int in the first call, String in the second.

Generic classes

case class Box[A](value: A):
  def map[B](f: A => B): Box[B] = Box(f(value))

class Stack[A]:
  private var items: List[A] = Nil
  def push(item: A): Unit = items = item :: items
  def pop(): Option[A] =
    val top = items.headOption
    items = items.drop(1)
    top

@main def genericClasses(): Unit =
  println(Box(21).map(_ * 2))
  println(Box("scala").map(_.length))

  val stack = Stack[String]()
  stack.push("a")
  stack.push("b")
  println(stack.pop())
  println(stack.pop())
  println(stack.pop())
Box(42)
Box(5)
Some(b)
Some(a)
None

Bounds

Upper bounds (A <: Shape) require a type parameter to be a subtype of something, so you can use its members:

trait Animal:
  def name: String
  def sound: String

case class Dog(name: String) extends Animal:
  def sound = "Woof"

case class Cat(name: String) extends Animal:
  def sound = "Meow"

def loudest[A <: Animal](animals: List[A]): A = animals.maxBy(_.sound.length)

@main def bounds(): Unit =
  val dogs = List(Dog("Rex"), Dog("Fido"))
  val winner: Dog = loudest(dogs)
  println(winner)
  println(s"${Cat("Tom").name} says ${Cat("Tom").sound}")
Dog(Rex)
Tom says Meow

The result type is Dog, not just Animal — the bound lets loudest call sound while still returning the precise type it was given.

Level 3 covers variance (+A, -A) and higher-kinded types.