scalaadvanced
Variance and Type Bounds
Understand covariance, contravariance, and type bounds: upper bounds, lower bounds, and context bounds.
scalaPress ⌘/Ctrl + Shift + C to copy
// Covariance (+T): if A <: B then F[A] <: F[B]
class Box[+T](val value: T):
// Can only use T in "out" position (return types)
def get: T = value
// Cannot: def set(v: T) — T in "in" position
// Contravariance (-T): if A <: B then F[B] <: F[A]
trait Printer[-T]:
def print(value: T): Unit
class AnimalPrinter extends Printer[Animal]:
def print(value: Animal): Unit = println(s"Animal: ${value.name}")
class CatPrinter extends Printer[Cat]:
def print(value: Cat): Unit = println(s"Cat: ${value.name}, lives: ${value.lives}")
trait Animal:
def name: String
case class Cat(name: String, lives: Int) extends Animal
case class Dog(name: String, breed: String) extends Animal
// Upper bound (<:): T must be subtype of Bound
def findMax[T <: Comparable[T]](items: List[T]): T =
items.reduce((a, b) => if a.compareTo(b) >= 0 then a else b)
// Lower bound (>:): T must be supertype of Bound
class Stack[+T]:
private val items: List[T] = Nil
// push needs lower bound because T is covariant
def push[U >: T](item: U): Stack[U] = new Stack[U]:
override val items: List[U] = item :: Stack.this.items
def peek: Option[T] = items.headOption
def toList: List[T] = items
// Context bounds (: TypeClass)
def sorted[T: Ordering](items: List[T]): List[T] = items.sorted
def show[T: Show](value: T): String = summon[Show[T]].show(value)
trait Show[T]:
def show(value: T): String
given Show[Int] with
def show(value: Int) = s"Int($value)"
given Show[String] with
def show(value: String) = s"Str($value)"
// Multiple bounds
def process[T: Ordering: Show](items: List[T]): String =
val s = summon[Show[T]]
items.sorted.map(s.show).mkString(", ")
// F-bounded polymorphism
trait Builder[Self <: Builder[Self]]:
def addStep(step: String): Self
def build: String
class PipelineBuilder extends Builder[PipelineBuilder]:
private val steps = List.empty[String]
def addStep(step: String): PipelineBuilder =
val b = PipelineBuilder()
b
def build: String = steps.mkString(" -> ")
// Variance in practice: Function1[-T, +R]
// Input types are contravariant, output types are covariant
val animalToString: Animal => String = a => a.name
val catToString: Cat => String = animalToString // OK! contravariant input
val catFactory: () => Cat = () => Cat("Whiskers", 9)
val animalFactory: () => Animal = catFactory // OK! covariant output
@main def run(): Unit =
// Covariance
val catBox: Box[Cat] = Box(Cat("Felix", 7))
val animalBox: Box[Animal] = catBox // OK because Box is covariant
println(s"Animal box: ${animalBox.get.name}")
// Contravariance
val animalPrinter: Printer[Animal] = AnimalPrinter()
val catPrinter: Printer[Cat] = animalPrinter // OK! Printer is contravariant
catPrinter.print(Cat("Luna", 9))
// Type bounds
println(s"\nCat name: ${catToString(Cat("Milo", 5))}")
println(s"Animal factory: ${animalFactory().name}")
// Context bounds
println(s"\nSorted: ${sorted(List(3, 1, 4, 1, 5))}")
println(s"Show: ${show(42)}")
println(s"Process: ${process(List(3, 1, 2))}")Use Cases
- Type-safe generic containers
- Flexible API design
- Understanding subtyping relationships
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
scalaadvanced
Generics Variance and Type Bounds
Use Scala generics with covariance, contravariance, upper/lower bounds, and context bounds.
Best for: Type-safe container libraries
#scala#generics
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