为什么不检查对象私有或对象保护定义的方差位置是否安全?

时间:2013-05-07 21:27:04

标签: scala covariance contravariance

我了解到Scala不会检查对象私有(private[this])或对象保护(protected[this])定义的方差位置。为什么不检查它们是否安全?

我已经阅读了一些与之相关的材料,但未能找到完整的答案。首先,Odersky等人的“Scala编程”说:

  

http://www.artima.com/pins1ed/type-parameterization.html#19.7

     

事实证明,从定义它们的同一对象访问变量不会导致方差问题。直观的解释是,为了构造一个方差会导致类型错误的情况,你需要引用一个包含对象,该对象具有比定义对象的类型更静态的类型。

我不确定作者的意思是“a 包含对象”和“静态弱类型”。这里更优选代码示例。

其次,“senia”在Scala Modifiers and Type parametrization中给出了一个很好的例子,它显示了类 - 私有(private)字段可能带有差异的问题。 这个例子让我相信为什么应该检查类私有成员的差异位置,但是没有给出我们不必检查对象私有/受保护定义的原因的答案。我知道像getOtherCache()这样的代码不能用object-private字段写。但它并未证明对象 - 私有/预测定义的无害性,我们还没有编写一个程序,对象 - 私有/预测定义会导致方差问题。

第三,在讨论如何在Scala中实现函数memoization时,Michid简要地提到了这个主题:

  

http://michid.wordpress.com/2009/02/23/function_mem/

     
class Memoize1[-T, +R](f: T => R) extends (T => R) {
  ...
  private[this] val vals = mutable.Map.empty[T, R]
  ...
}
     

但是,由于vals仅从其包含实例访问,因此不会导致方差问题。

不幸的是,它没有回答我的问题“与方差相关的访问控制如何(或为什么)?”。

您能否更详细地解释不检查对象 - 私有/受保护定义的方差位置(或提供一些参考)的基本原理?

1 个答案:

答案 0 :(得分:5)

只有在对象的编译时和运行时类型不同时才会出现方差问题:

val a: List[Any] = List("foo"): List[String]

此处a具有静态较弱的类型(List[Any])而非定义的List[String])。此外,这同样适用于包含对象(即列表的元素)。 (静态类型Any,已定义类型String)。

如果我们有对象私有(或受对象保护)字段,则不会发生这种情况:

trait A[-T] {
  protected[this] val x: T
}

当我们访问x时,我们可以确定它实际上是T类型,即使A是反变量的,因为this引用不能 - 在某个地方施展。 (我们总是完全了解自己的类型。)

所以当我们回到奥德斯基的话时,让我们来看看:

val cont: A[String] = new A[Any] { ... }
cont.x // BAD! Is `Any`, not `String`

cont是对具有静态弱于定义的对象的引用,这就是不允许引用x的原因。使用this指针不会发生这种上转情况,因此以下情况可以:

trait B[-T] extends A[T] {
  def foo() {
    // here, this has always the most specific type.
    val tmp: T = this.x
    // do stuff
  }
}