I\'m creating a memoization class.
Each class memoizes a function type and has the following definition:
class MemoizedFunction1[-T1, +R](f: T1 => R)
Not that I understand all of it, but this is addressed in section 4.5 (Variance Annotations) of the Scala Language Specification 2.9 on page 45
References to the type parameters in object-private or object-protected values, variables, or methods (§5.2) of the class are not checked for their variance position. In these members the type parameter may appear anywhere without restricting its legal variance annotations.
To simplify your example, according to the spec, this is fine:
class Inv[T]
class Foo[-T] {
private[this] val a: Inv[T] = sys.error("compiles")
protected[this] val b: Inv[T] = sys.error("compiles")
}
But if you remove [this]
it will complain. At some level it makes sense since if it is not object private or protected the contravariant return type could leak outside the object and cause a runtime error.
Programming in Scala touches on this topic in Section 19.7 Object private data: "object private members can be accessed only from within the object in which they are defined. It turns out that accesses to variables from the same object in which they are defined do not cause problems with variance."
Let's assume you can remove [this]
.
Without [this]
you can add method getOtherCache
:
class MemoizedFunction1[-T1, +R](f: T1 => R) {
private val cache = mutable.Map[T1, R]() // trait Map[A, B] extends Iterable[(A, B)] with Map[A, B] with MapLike[A, B, Map[A, B]]
def apply(t: T1): R = cache.getOrElseUpdate(t,f(t))
def getOtherCache(other: MemoizedFunction1[T1, R]) {
val otherCache: mutable.Map[T1, R] = other.cache;
}
}
class A
class B extends A
val mf1: MemoizedFunction1[B, B] = new MemoizedFunction1[B, B](b => b)
val mf2: MemoizedFunction1[B, B] = new MemoizedFunction1[A, B](a => new B)
// mf2 is MemoizedFunction1[B, B]
// mf2 contains mutable.Map[A, B]
mf1.getOtherCache(mf2) //Error! mf2.cache is NOT mutable.Map[B, B]!