Last active
August 28, 2019 16:27
-
-
Save programaker/b6f5e36b909333fff3c7309e8368a9d6 to your computer and use it in GitHub Desktop.
Scala: about variance
This file contains 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 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