【问题标题】:Why is the parameter type generalized for method specialization on override?为什么参数类型被泛化为覆盖上的方法特化?
【发布时间】:2018-07-07 15:21:37
【问题描述】:

我正在阅读的这本书刚刚介绍了包含、协变、逆变的概念及其对编程语言设计的影响。现在,在关于方法专业化的部分,我遇到了麻烦。

书中指出,当我们在子类中重写方法时,参数类型可能会被泛化,结果类型可能会被特化。然而,本书认为,对于没有被覆盖而是继承的方法,另一种类型的方法特化正在发挥作用,其中参数类型被特化,结果类型被泛化,因为我们可以将 self 关键字解释为参数:

“还有另一种形式的方法特化,它通过继承隐式发生。在 C 的方法中出现的 self 可以被认为是 C 类型,因为所有绑定到 self 的对象都具有 C 类型或 C 的子类型. 当 C 的方法被 C' 继承时,同样出现的 self 可以类似地被认为是类型 C'。因此 self 的类型默默地专门用于继承(协变!)。”

这是我的问题:我们不能将 self 关键字视为重写方法中的协变参数吗?然后我们最终会使用 this 关键字作为协变参数,即使我们刚刚确定,由于替换原则,重写方法的参数需要是逆变的。我忽略了什么吗?

感谢您的帮助!

【问题讨论】:

  • 对不起,可能是我缺乏知识,但是“将self关键字视为协变参数”是什么意思?如果可能的话,也许我只需要一个例子。
  • 如果你调用一个方法,你会隐式传递一个参数,即将self-keyword(有时称为this-keyword)绑定到该方法所属的对象。因此,像 myObj.m(arg1) 这样的方法可以等效地实现为函数 m(myObj, arg1) 。这就是 self 关键字可以解释为参数的原因。由于上述原因(第 3 段),该论点是协变的。
  • 我有点好奇,您是否发现了有关此主题的更多信息,或者我在回答中所做的“研究”是否足够?
  • 据我所知,现在不应将 this-arg 视为跨类中的方法及其在子类中的覆盖的协变,因为创建协变的动态是动态绑定。我的猜测是,答案与这样一个事实有关,即当两者之间存在覆盖时,来自继承方法的调用永远不能动态绑定到层次结构更上层的类的方法(除非你使用 super 关键字 I猜)。
  • 包含和 self 关键字的两个概念似乎确实有些矛盾,所以你的答案是正确的!本书(A Theory of Objects by Abadi 和 Cardelli,如果您感兴趣的话)对此问题进行了一定的论述。它们可以通过不同的方式进行调和和平衡,例如特殊的 Self 返回类型,或者对包容的较弱定义。老实说,我想我不能告诉你答案,我想我自己也没有得出结论。我对这个话题很陌生,但我会继续挖掘 ;) 无论如何,谢谢你的帮助!

标签: oop covariance contravariance


【解决方案1】:

在编程语言中实现变体

...当我们在子类中重写方法时,参数类型可能是泛化的(协变),结果类型可能是特化的(逆变

尽管这可能是真的,但这取决于具体的语言,它是否真的实现了这个功能。我找到了examples on wiki

  • C++ 和 Java 只实现协变返回类型和方法 参数类型是不变的。

  • C# 没有实现任何一种变体(因此两者都是不变的)。

  • 有一个具有逆变参数类型和协变返回类型的语言(Sather)示例 - 这就是您提到的。

  • 但是,也有一个(埃菲尔)具有协变返回和参数类型,但这种可能通常会导致运行时错误。

控制和“剩余”参数

There 也是一个很好的段落,在控制参数和“剩余”参数之间划分参数。控制的是协变的,非控制的是逆变的。这是关于多种调度语言的,尽管您肯定是指一种单一的调度语言。但即使只有一个控制参数 (self/this)。

这是一段(我没有时间研究paper it is referring to,如果您有时间,请随时阅读并发布您的发现):

Giuseppe Castagna[3] 观察到,在具有多重分派的类型化语言中,泛型函数可以有一些控制分派的参数和一些“剩余 " 没有的论点。因为方法选择规则选择最具体的适用方法,如果一个方法覆盖另一个方法,那么覆盖的方法将具有更具体的控制参数类型。另一方面,为了确保类型安全,语言仍然必须要求 left-over 参数至少具有通用性。使用前面的术语,用于运行时方法选择的类型是协变的,而不用于方法的运行时方法选择的类型是逆变的

像 Java 这样的传统单调度语言也遵守这条规则:只有一个参数用于方法选择(接收器对象,作为隐藏参数传递给方法this),实际上是@987654328 的类型@ 在覆盖方法内部比在超类中更专业。

问题

根据段落,我假设 self 参数本质上不是常规方法参数(可能是逆变的),因为self 是另一种参数 - 控制参数 - 协变的

...尽管我们刚刚确定,作为替换原则的结果,被覆盖方法的参数需要是逆变的。

嗯,看起来不是全部。

【讨论】:

    猜你喜欢
    • 2015-05-22
    • 2012-01-08
    • 2018-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多