Last active
August 7, 2022 16:35
-
-
Save nicerobot/4745767 to your computer and use it in GitHub Desktop.
Scala generics, "simplified", covariance and contravariance.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
nice and concise explanation to generics in Scala, thanks a lot!!