Skip to content

Instantly share code, notes, and snippets.

@programaker
Last active August 28, 2019 16:27
Show Gist options
  • Save programaker/b6f5e36b909333fff3c7309e8368a9d6 to your computer and use it in GitHub Desktop.
Save programaker/b6f5e36b909333fff3c7309e8368a9d6 to your computer and use it in GitHub Desktop.
Scala: about variance
class Producer[+X](x: X) {
def produce: X = x
}
class Consumer[-X](name: String) {
def consume(x: X): Unit = println(s">>> $name is consuming $x polimorfically")
}
//--------------------------------------
class A { override def toString: String = "A" }
class B extends A { override def toString: String = "B" }
//--------------------------------------
val a = new A
val b = new B
val prodA = new Producer[A](a)
val consA = new Consumer[A]("consA")
consA.consume(prodA.produce)
val prodB = new Producer[B](b)
val consB = new Consumer[B]("consB")
consB.consume(prodB.produce)
//Consumer[A] can consume B's due to normal polimorphism (B extends A).
//Nothing special! Nothing to do with variance!
consA.consume(prodB.produce)
//Variance is about the relationship among "instances" of a parameterized type/type constructor:
//
//If B extends A and Producer is covariant,
//then I can attribute a Producer[B] in a Producer[A] val
//"+" sign => the val can hold A's or greater types
val prodA2: Producer[A] = prodB
//
//If B extends A and Consumer is contravariant,
//then I can attribute a Consumer[A] in a Consumer[B] val
//"-" sign => the val can hold B's or lesser types
val consB2: Consumer[B] = consA
//Functions are contravariant in the input and covariant in the output - Function1[-A, +B]
def stringA(a: A): String = a.toString
def stringB(b: B): String = b.toString
//
//printB needs a function that knows how to transform a B into a String, but
//because of the contravariance in the input, both stringB and stringA
//can be passed! stringA can convert B's into Strings by polimorphism
def printB(f: B => String, b: B): Unit = println(s">=> printB ${f(b)}")
println(">-> " + stringA(a))
println(">-> " + stringA(b))
printB(stringB, b)
printB(stringA, b)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment