Scala 的特质为何不是真正的特质?
最近有人告诉我,Scala 的特征不是“真正的”特征,它们实际上只是混合。不幸的是,我没有机会问他为什么。有人知道他的意思吗?
编辑: 作为“特质”的定义,我参考了 Nathanael Schärli 的论文和概念论文介绍特质。大多数 mixin 和/或多继承实现中似乎缺少的一项关键功能是在导入方法时重命名方法以避免冲突/歧义的能力。 Scala 能做到吗?
Someone recently told me that Scala's traits aren't "true" traits, and that they were really just mixins. Unfortunately, I didn't get the opportunity to ask him why. Does anyone have an idea what he meant?
Edit:
As a definition of "traits," I have been referring to Nathanael Schärli’s dissertation and concept paper introducing traits. One key feature that seems to be missing from most mixin and/or multiple inheritance implementations is the ability to rename methods when you import them to avoid collision/ambiguity. Can Scala do that?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我认为这可能与 Scala 中的内容有关,而不是原始 论文中提出的内容有关。
我也曾经思考过这个问题,抛开实现差异不谈,我得出的结论是 Scala 的特性确实有一些不足之处。 Scala 让您组合但不排除方法的方式很奇怪。为了避免冲突,它从其他语言借用了一种称为方法解析顺序(或 Scala 语言中的线性化)的东西。支持多重继承的语言有一个众所周知的问题,我将大胆地将 Scala 归类为该组的成员。问题是它太复杂且耗时,难以理解。
Scala 的方法解析顺序是一个奇怪的野兽,它有自己的方法分派算法。它不是 Dylan 的 C3,它在 Python 中使用,有一些值得注意的问题,但具有所有与之相关的问题。更糟糕的是,我可以通过调用 Python 对象的
.mro()
方法来查找其 MRO。 Scala 中没有类似的东西。我可以告诉你,每次我需要查找某个方法将解析到哪里时,我不太喜欢在脑海中运行 Scala MRO 算法。
I think that probably has to do with what's in Scala as opposed to what was proposed in the original paper.
I once thought about this question too, implementation differences aside, I've come to the conclusion that traits in Scala indeed left something to be desired. The way that Scala let you compose but not exclude methods is strange. To avoid conflicts, it had borrowed something called a method resolution order (or linearization in Scala-speak) from other languages. There's a problem well-known for languages that support multiple-inheritance, which I will boldly classify Scala as a member of this group. The problem is that it's too complicated and time-consuming to understand.
Scala's method resolution order is a strange beast, it has its own algorithm for method dispatch. It's not Dylan's C3, which is used in Python, with some notable problems, but has all the problems that are associated with it. Worse, I can look up a Python object's MRO by calling its
.mro()
method. There's no equivalent in Scala.I can tell you I'm not very fond to running the Scala MRO algorithm in my head for every time I need to look up where a method will be resolved to.
mixin 和 Trait 之间的一个关键区别是 mixin 有字段,而 Trait 没有。转述原论文,有一个特征:
乍一看,第三点看起来像是被破坏了在Scala 实现中。但是,特征只能访问受隐式 getter 和 setter 保护的公共字段。该论文接着描述了这对于特征的实现是可以接受的。
您指出,特征的一个关键特性是,在导入方法时可以对其进行重命名。考虑到 JVM 的限制,这是不可能的。对此的连贯讨论可以在这里找到: http ://scala-programming-language.1934581.n4.nabble.com/Trait-method-aliasing-td2322026.html,特别是 David Pollak 的帖子。
最后,我对你的一般性问题的回答是“有点”。详细来说,虽然 Scala 特征不是本文定义的严格特征,但它们也不是严格的 mixins。不管怎样,最好像使用特性一样使用它们,并遵守它们的设计原则。
One key different between mixins and traits is that mixins have fields, whereas traits do not. Paraphrasing from the original paper, a trait:
At first glance the third point looks like it is broken in the Scala implementation. However, traits can only access public fields, which are protected by implicit getters and setters. The paper goes on to describe that this is acceptable for the implementation of traits.
You point out that a key feature of traits is that methods can be renamed when you import them. This is not possible given the constraints of the JVM. A coherent discussion of this can be found here: http://scala-programming-language.1934581.n4.nabble.com/Trait-method-aliasing-td2322026.html, particularly the posts by David Pollak.
Finally, my answer to your general question is "sort of". To elaborate, whilst Scala traits are not strictly traits as defined by the paper, they are not strictly mixins either. Either way, it is probably best to use them like they were traits and keep to their design principles.
不可以,Scala 无法在导入时重命名。
我想知道那是如何运作的。如果特征
T
的方法m
在对象o
中重命名为m2
,pm
会怎样?如果p
是T
类型的参数,并且o
已通过它传递,那么 code> 是否可以解析?No, Scala cannot rename on import.
I wonder how that would even work. If method
m
of traitT
is renamed tom2
in objecto
, how wouldp.m
be resolved ifp
is a parameter of typeT
, ando
has been passed through it?