Skip to content

Instantly share code, notes, and snippets.

@nicerobot
Last active August 7, 2022 16:35
Show Gist options
  • Save nicerobot/4745767 to your computer and use it in GitHub Desktop.
Save nicerobot/4745767 to your computer and use it in GitHub Desktop.
Scala generics, "simplified", covariance and contravariance.
// This is an example of how to reason about covariance vs contravariance.
// Between the two co*.reasoning.scala examples, the following compiles but meaning is slightly different due to the class hierarchy.
type SHORT = A[SMALL]
type INT = A[MEDIUM]
type LONG = A[LARGE]
val s:SHORT = new SHORT()
val i:INT = s
val l:LONG = i
// Compare this to the covariance.reasoning.scala example. Notice the class hierarchy.
trait SMALL
trait MEDIUM extends SMALL
trait LARGE extends MEDIUM
class A[-T]
// See co.reasoning.scala
// Compare this to the contravariance.reasoning.scala example. Notice the class hierarchy.
trait LARGE
trait MEDIUM extends LARGE
trait SMALL extends MEDIUM
class A[+T]
// See co.reasoning.scala
class A
class B extends A
class C extends B
// Upper Bounds
class D[T <: B] // T must be a B. i.e. for any T, it is a B or a subclass of B.
// new D[A]() // <- type error
new D[B]()
new D[C]()
// Lower Bounds
class E[T >: B] // B must be a T. i.e. for any T, B must also be that same type.
new E[A]()
new E[B]()
// new E[C]() // <- type error
trait X
trait Y extends X
trait Z extends Y
// Contravariance
class A[-T] // contravariant in T
// Given:
val ax : A[X] = new A[X]()
// You can assign any A[T] to an A[Y] as long as T >: Y.
// i.e. if Y is a T, an A[Y] is an A[T]
val ayx : A[Y] = ax
// And you can assign any A[T] to an A[Z] as long as T >: Z.
// i.e. if T is a Z, an A[Z] is an A[T]
val azx : A[Z] = ax
val azy : A[Z] = ayx
trait X
trait Y extends X
trait Z extends Y
// Covariance
class A[+T] // covariant in T
// Given:
val az : A[Z] = new A[Z]()
// You can assign any A[T] to an A[Y] as long as T <: Y.
// i.e. if T is a Y, any A[T] is an A[Y]
val ayz : A[Y] = az
// You can assign any A[T] to axy and axz as long as T <: X.
// i.e. if T is an X, any A[T] is an A[X]
val axy : A[X] = ayz
val axz : A[X] = az
@batakpout
Copy link

nice and concise explanation to generics in Scala, thanks a lot!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment