Skip to content

Commit 083544d

Browse files
author
Luis Reis
committed
fix exercise for type contravariance to remove mutation
1 parent 1d75d07 commit 083544d

File tree

2 files changed

+27
-17
lines changed

2 files changed

+27
-17
lines changed

src/main/scala/stdlib/TypeVariance.scala

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -99,25 +99,26 @@ object TypeVariance extends FlatSpec with Matchers with org.scalaexercises.defin
9999
}
100100

101101
/** Declaring - indicates contravariance variance. Using - you can apply any container with a certain type to a container with a superclass of that type. This is reverse to covariant. In our example, we can set a citrus basket to an orange or tangelo basket. Since an orange or tangelo basket are a citrus basket. Contravariance is the opposite of covariance:
102-
* //TODO rework without mutability
103-
*
104-
* def contravarianceVarianceTypeVariance(res0: String, res1: String, res2: String, res3: String) {
105-
* class MyContainer[-A](val a: A)(implicit manifest: scala.reflect.Manifest[A]) {
106-
* def contents = manifest.runtimeClass.getSimpleName
107-
* }
108-
*
109-
* val citrusBasket: MyContainer[Citrus] = new MyContainer[Citrus](new Orange)
110-
* citrusBasket.contents should be(res0)
111-
* val orangeBasket: MyContainer[Orange] = new MyContainer[Citrus](new Tangelo)
112-
* orangeBasket.contents should be(res1)
113-
* val tangeloBasket: MyContainer[Tangelo] = new MyContainer[Citrus](new Orange)
114-
* tangeloBasket.contents should be(res2)
115-
*
116-
* val orangeBasketReally: MyContainer[Orange] = tangeloBasket.asInstanceOf[MyContainer[Orange]]
117-
* orangeBasketReally.contents should be(res3)
118-
* }
119102
*/
120103

104+
def contravarianceVarianceTypeVariance(res0: String, res1: String, res2: String, res3: String) {
105+
class MyContainer[-A](a: A)(implicit manifest: scala.reflect.Manifest[A]) { //Can't receive a val because it would be in a covariant position
106+
def contents = manifest.runtimeClass.getSimpleName
107+
}
108+
109+
val citrusBasket: MyContainer[Citrus] = new MyContainer[Citrus](new Orange)
110+
citrusBasket.contents should be(res0)
111+
val orangeBasket: MyContainer[Orange] = new MyContainer[Citrus](new Tangelo)
112+
orangeBasket.contents should be(res1)
113+
val tangeloBasket: MyContainer[Tangelo] = new MyContainer[Citrus](new Orange)
114+
tangeloBasket.contents should be(res2)
115+
val bananaBasket: MyContainer[Banana] = new MyContainer[Fruit](new Apple)
116+
bananaBasket.contents should be(res3)
117+
118+
//val fruitBasket: MyContainer[Fruit] = new MyContainer[Citrus](new Orange) //Bad!
119+
//val wrongCitrusBasket: MyContainer[Citrus] = new MyContainer[Orange](new Orange) //Bad!
120+
}
121+
121122
/** Declaring neither `-`/`+`, indicates invariance variance. You cannot use a superclass variable reference (\"contravariant\" position) or a subclass variable reference (\"covariant\" position) of that type. In our example, this means that if you create a citrus basket you can only reference that citrus basket with a citrus variable only.
122123
*
123124
* Invariance means you need to specify the type exactly:

src/test/scala/stdlib/TypeVarianceSpec.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,15 @@ class TypeVarianceSpec extends Spec with Checkers {
5252
)
5353
}
5454

55+
def `contravariance` = {
56+
check(
57+
Test.testSuccess(
58+
TypeVariance.contravarianceVarianceTypeVariance _,
59+
"Citrus" :: "Citrus" :: "Citrus" :: "Fruit" :: HNil
60+
)
61+
)
62+
}
63+
5564
def `invariance` = {
5665
check(
5766
Test.testSuccess(

0 commit comments

Comments
 (0)