scalaadvanced
Generics Variance and Type Bounds
Use Scala generics with covariance, contravariance, upper/lower bounds, and context bounds.
scalaPress ⌘/Ctrl + Shift + C to copy
// Covariant container (+T): if A <: B, then Box[A] <: Box[B]
sealed trait Box[+A]:
def map[B](f: A => B): Box[B]
def flatMap[B](f: A => Box[B]): Box[B]
case class Full[+A](value: A) extends Box[A]:
def map[B](f: A => B): Box[B] = Full(f(value))
def flatMap[B](f: A => Box[B]): Box[B] = f(value)
case object Empty extends Box[Nothing]:
def map[B](f: Nothing => B): Box[B] = Empty
def flatMap[B](f: Nothing => Box[B]): Box[B] = Empty
// Contravariant (-T): Printer[Animal] <: Printer[Dog]
trait Printer[-A]:
def print(value: A): String
class AnimalPrinter extends Printer[Animal]:
def print(value: Animal): String = s"Animal: ${value.name}"
trait Animal:
def name: String
case class Dog(name: String, breed: String) extends Animal
case class Cat(name: String) extends Animal
// Upper bound: T must be subtype of Comparable
def maxOf[T <: Comparable[T]](a: T, b: T): T =
if a.compareTo(b) >= 0 then a else b
// Lower bound: T must be supertype of A
def prepend[A, B >: A](list: List[A], elem: B): List[B] =
elem :: list
// Context bound: requires given instance
def showAll[T: Show](items: List[T]): String =
items.map(summon[Show[T]].show).mkString(", ")
trait Show[T]:
def show(value: T): String
given Show[Int] with
def show(value: Int): String = value.toString
given Show[String] with
def show(value: String): String = s"\"$value\""
// Type class derivation
given [A: Show, B: Show]: Show[(A, B)] with
def show(value: (A, B)): String =
s"(${summon[Show[A]].show(value._1)}, ${summon[Show[B]].show(value._2)})"
@main def run(): Unit =
// Covariance
val dogBox: Box[Dog] = Full(Dog("Rex", "Lab"))
val animalBox: Box[Animal] = dogBox // OK: Box is covariant
println(animalBox.map(_.name))
val empty: Box[Dog] = Empty
println(empty.map(_.name)) // Empty
// Contravariance
val animalPrinter: Printer[Animal] = AnimalPrinter()
val dogPrinter: Printer[Dog] = animalPrinter // OK: Printer is contravariant
println(dogPrinter.print(Dog("Rex", "Lab")))
// Context bounds
println(showAll(List(1, 2, 3)))
println(showAll(List("a", "b")))
println(showAll(List((1, "a"), (2, "b"))))Use Cases
- Type-safe container libraries
- Flexible API design with variance
- Type class patterns with context bounds
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
scalaadvanced
Variance and Type Bounds
Understand covariance, contravariance, and type bounds: upper bounds, lower bounds, and context bounds.
Best for: Type-safe generic containers
#scala#variance
kotlinadvanced
Generics — Variance, Bounds, and Type Projections
Master Kotlin generics: in/out variance, upper bounds, type projections, and generic constraints.
Best for: Type-safe generic APIs and containers
#kotlin#generics
kotlinadvanced
Kotlin Generics Variance In Out Star
Understand Kotlin generics: declaration-site variance with in/out, type projections, and star projection.
Best for: Type-safe container hierarchies
#kotlin#generics
scalabeginner
Scala Hello World Application
Create a basic Scala application with main method, string interpolation, and val/var basics.
Best for: Getting started with Scala
#scala#basics