0

(强调我的)

字段和函数的协变重新定义没有问题,但是 参数的协变重新定义确实会产生一个问题,即非法类型可以作为参数传递。

但是,如果重新定义字段和函数类型协变没有问题,那么重新定义参数的类型协变怎么会导致麻烦呢?

协变重新定义等于子类型化,对吧?子类型可以代替它们的超类型!

有什么问题?

4

2 回答 2

1

问题不在于协方差本身。(特别是,如果它是逆变的,那么按合同设计是不可能的,因为后代类的特征中的参数类型不必在其父类中具有可用的特征。使用协方差就不会有这样的问题。)

有问题的是协方差与多态性的结合。例如

class A feature
    foo (a: A) do a.bar end -- (1)
    bar do end
end
class B inherit A redefine foo end feature
    foo (a: B) do a.qux end -- (2)
    qux do end
end

现在下面的代码会崩溃:

a: A; b: B
...
create b
a := b
a.foo (create {A})

实际上,a.foo会调用版本 (2),因为a它附加到类型为 的对象B。但是,传递给此功能的参数将是类型A。并且A没有qux导致运行时错误的功能。这种错误称为 CAT 调用(更改可用性或类型)。

解决这个问题的方法是避免将协变与多态一起使用,即调用不应该是多态的,或者不应该对参数进行协变重新声明。该解决方案的工作正在进行中。

于 2016-12-13T12:44:15.327 回答
0

“调用不应该是多态的,或者不应该有参数的协变重新声明。”

你怎么知道?

让我们稍微改变一下你的例子:

嗡嗡声(a_a:A)做a_a.foo(创建{A})结束

这看起来很无辜。但是如果buzz 接收到一个动态类型B 的参数,你仍然会得到catcall。嗡嗡声的作者很可能处于未知B存在的情况。

我认为你需要放弃“一个电话不应该是多态的或”的建议。简单地禁止参数的协变重新声明。

于 2016-12-14T08:35:11.943 回答