[英]Why do lower type bounds change the variance position?
The Scala Language Specification (Section 4.5 on Variance Annotations, p. 44) says Scala语言规范(Variance Annotations第4.5节,第44页)说
Using the first point above, it is easy to see (at least formally) that 使用上面的第一点,很容易看到(至少正式)
trait Covariant[+A] {
def problematic[B <: A](x : B)
}
produces the error message 生成错误消息
error: covariant type A occurs in contravariant position in type >: Nothing <: A of type B
def problematic[B <: A](x : B)
and using the first and the second point it is easy to see that 并且使用第一点和第二点很容易看出
trait Contravariant[-A] {
def problematic[B >: A](x : B)
}
produces the error message 生成错误消息
error: contravariant type A occurs in covariant position in type >: A <: Any of type B
def problematic[B >: A](x : B)
As I mention, it's easy to see formally (ie, following the rules for variance annotations) why these errors occur. 正如我所提到的,很容易正式看到(即遵循方差注释规则)为什么会出现这些错误。 However, I can not come up with an example illustrating the need for these restrictions.
但是,我无法想出一个说明需要这些限制的例子。 In contrast, it is very easy to come up with examples that illustrate why method parameters should change variance positions, see eg Checking Variance Annotations .
相比之下,很容易想出说明为什么方法参数应该改变方差位置的例子,参见例如检查方差注释 。
So, my question is the following: Assuming, the two pieces of codes above were allowed, what are the examples of problems that arise? 所以,我的问题如下:假设,上面的两段代码被允许,出现问题的例子是什么? This means, I'm looking for examples similar to this one that illustrate what could go wrong in case the two rules cited above were not used.
这意味着,我正在寻找类似于这个的例子,说明如果不使用上面提到的两个规则会出现什么问题。 I'm particularly interested in the example involving lower type bounds.
我对涉及较低类型边界的示例特别感兴趣。
Note that the answer to Scala type bounds & variance leaves this particular question open, whereas the answer given in The "lower bound" will reverse the variance of a type, but why? 请注意, Scala类型边界和方差的答案会打开这个特定问题,而“下限”中给出的答案将反转类型的方差,但为什么呢? seems wrong to me.
对我来说似乎不对。
Edit: I think the first case can be handled as follows (adapting the example cited above). 编辑:我认为第一种情况可以如下处理(适应上面引用的例子)。 Assume, the following was allowed
假设,允许以下内容
trait Queue[+T] {
def head : T
def tail : Queue[T]
def enqueue[U <: T](x : U) : Queue[T]
}
Then we could implement 然后我们可以实施
class QueueImplementation[+T] extends Queue[T] {
/* ... implement Queue here ... */
}
class StrangeIntQueue extends QueueImplementation[Int] {
override def enqueue[U <: Int](x : U) : Queue[Int] = {
println(math.sqrt(x))
super.enqueue(x)
}
}
and use it as 并用它作为
val x : Queue[Any] = new StrangeIntQueue
x.enqueue("abc")
which is clearly troublesome. 这显然很麻烦。 However, I can not see how to adapt this in order to show that the combination "contravariant type parameter + lower type bound" is also problematic?
但是,我看不出如何调整这个以表明“逆变型参数+下限类型”的组合也存在问题?
Use the ++
method from List
to see why the restrictions are needed. 使用
List
的++
方法查看为什么需要这些限制。 Due note, this requires that ++
produce a List[B]
: 需要注意的是,这需要
++
生成一个List[B]
:
def ++[B](that: GenTraversableOnce[B]): List[B]
with a full signature of 完整的签名
def ++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That
So why is it important that [B >: A]
. 那么为什么重要的是
[B >: A]
。 Well, what if we want to combine something such that 那么,如果我们想要结合这样的东西呢?
trait Foo
trait Bar extends Foo
and we have a method that has a signature 我们有一个有签名的方法
def op(that: List[Foo], other: Foo): List[Foo] = that ++ List(other)
I can pass it a list of type Bar
but in order to be able to return it as a List[Foo]
I must make the condition that Foo >: Bar
so that I can actually do the following 我可以传递一个类型为
Bar
的列表但是为了能够将它作为List[Foo]
返回List[Foo]
我必须使条件Foo >: Bar
以便我可以实际执行以下操作
def see(that: List[Bar]): List[Foo] = op(that, myFoo)
which essentially is doing a List[Bar] ++ List[Foo]
to return a type of List[Foo]
as expressed though a List[Foo]
type. 它本质上是做一个
List[Bar] ++ List[Foo]
来返回一个List[Foo]
类型,如List[Foo]
类型所表达的那样。 That is why the flip happens. 这就是翻转发生的原因。
Now if I tried to enforce that Foo <: Bar
I would immediately run into the issue that List[Bar] ++ List[Foo]
could not return a list of type Foo
(not to mention having it conflict with the definition above.) It would only ever be able to return a List
of the least upper bound. 现在,如果我试图强制执行
Foo <: Bar
我会立即遇到List[Bar] ++ List[Foo]
无法返回Foo
类型列表的问题(更不用说它与上面的定义冲突了。)它只能返回最小上限的List
。
Let's suppose we allow for a class to have a type parameter [-T]
and a method on that class to have [U >: T]
... 假设我们允许类具有类型参数
[-T]
并且该类的方法具有[U >: T]
...
for come class hierarchy
Dog <: Mammal <: Animal
class Contra[-X](x: X){
def problem[Y >: X](y: Y): Y = x // X<:Y so this would be valid
}
val cMammal:Contra[Mammal] = new Contra(new Mammal)
val a:Animal = cMammal problem new Animal // Animal >: Mammal, this is fine
val m:Mammal = cMammal problem new Mammal // Mammal >: Mammal, this is fine
val d:Mammal = cMammal problem new Dog // (Dog upcasts to Mammal) >: Mammal, this is fine
val cDog:Contra[Dog] = cMammal // Valid assignment
val a:Animal = cDog problem new Animal // Animal >: Mammal, this is fine
val m:Mammal = cDog problem new Mammal // Mammal >: Mammal, this is fine
val d:Dog = cDog problem new Dog // AAAHHHHHHH!!!!!!
This last line would type check, cDog problem new Dog
would actually return a Mammal
. 这最后一行会输入检查,
cDog problem new Dog
实际上会返回一个Mammal
。 This is clearly not a good thing. 这显然不是一件好事。 Thankfully the type system doesn't actually let us do this.
值得庆幸的是,类型系统实际上并没有让我们这样做。
QED contravariant type parameter + lower type bound not a good idea to mix. QED逆变型参数+低级类型绑定不是一个好主意混合。
I hope this example helps. 我希望这个例子有所帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.