Scala中的Nothing是其他所有类型的子类型


19

我正在上马丁·奥德斯基(Martin Odersky)的scala函数编程课程,到目前为止,我已经学到了两件事,但它们没有任何意义:

  1. Scala不支持多重继承
  2. Nothing 是其他所有类型的子类型

这两个语句不能同时存在,那么这是如何完成的呢?“其他类型的子类型”到底是什么意思

编辑1

Scala API中Nothing其定义为abstract final class Nothing extends Any...那么如何扩展其他类?


该页面可能会有所帮助:artima.com/pins1ed/scalas-hierarchy.html
jhewlett

至于我可以看到它被定义为“最后的特质没什么延伸的任何” scala-lang.org/api/2.7.6/scala/Nothing.html
书斋

8
您在混淆类型和类。那两个是完全不同的东西。不幸的是,您不是唯一被这种区分所迷惑的人,而且不幸,确实有些困惑的人恰巧是流行语言(如Java,C#和C ++)的设计者。它并不是说它Nothing是所有其他类的子类。它说它是所有其他类型类型
约尔格W¯¯米塔格

1
@delnan:Java的接口直接来自Smalltalk的协议。在Smalltalk中,只有协议是类型,而类不是。在Java中,这两个接口类类型。错了 类不是类型,只有接口是类型。所有这些语言都具有类型而非类的事实是无关紧要的。问题在于,在那些语言中,类是类型,这是错误的。
约尔格W¯¯米塔格

1
@JörgWMittag这是一条不同的说法,而且非常有争议(我倾向于认为这是有害的,但我不会将其归因于对打字的误解)。在这里讨论它没有意义。

Answers:


27

子类型化和继承是两件事!Nothing不会扩展所有内容,它是一个子类型,只会扩展Any

规范[第3.5.2节]有管理的子类型关系的特殊情况Nothing

§3.5.2符合性

  • [...]
  • 对于每种值类型
    Tscala.Nothing <: T <:scala.Any
  • 对于每个类型构造函数T(具有任意数量的类型参数)
    scala.Nothing <: T <: scala.Any
  • [...]

其中<:基本上是指“是”的子类型。

至于如何完成:我们不知道,这是编译器的魔力和实现细节。

一种语言经常会做您作为程序员无法做到的事情。作为与之对应的Nothing:Scala中的一切都继承了Any除了 Any。为什么不Any继承某些东西?你不能那样做。为什么Scala可以这样做?好吧,因为Scala设定了规则,而不是您。Nothing成为所有事物的子类型只是其另一实例。


10
顺便说一句:这与null可分配给Java中每种类型的字段完全相同。为什么会这样呢?是null每个类的实例吗?不可以,因为编译器会这样说。期。
约尔格W¯¯米塔格

8
如果我能投票一百次,我会的。混淆类型是Java之类的语言给我们带来的最糟糕的事情之一。
约尔格W¯¯米塔格

1
对于关于继承和子类型之间的区别的好奇的灵魂,请访问cmi.ac.in/~madhavan/courses/pl2006/lecturenotes/lecture-notes / ...但是我不买它-如果您继承(如extendsJava中那样,而不是像compose那样) )毕竟是为了进行子类型化。
greenoldman

11

当他说Scala不支持多重继承时,他指的是多次继承一个方法实现。当然,您可以在一个类中实现多个接口/特征,它们甚至可以定义相同的方法,但是由于特征线性化,您不会在不同的实现之间产生冲突。

通常,如果您有一个C1带有方法f()的类和一个C2也带有方法的类f(),则多重继承意味着您可以以某种方式继承的两个实现f()。这可能会导致各种问题,Scala只能通过让您从单个类继承来解决,而在具有多个特征的情况下,可以通过基于特征的顺序选择一个实现来解决这些问题。

至于Nothing事情真的很简单,因为什么都没有定义任何属性或方法。因此,您不会有任何继承冲突。但是我认为您最惊奇的是来自对多重继承的不同理解。

一旦您了解了特征线性化有效消除了继承的任何歧义,并且由于这个原因我们不将多重特征的继承称为多重继承,那么您就可以了。

关于如何实现:编译器最终对此负责。请参阅Scala语言规范第3.5.2节的一致性,其中的其他属性包括:

For every type constructor T (with any number of type parameters), scala.Nothing <: T <: scala.Any.

换句话说,如果要正确实现编译器,则必须Nothing按规范将编译器作为所有内容的子类型来处理。出于明显的原因,Nothing未将其定义为从加载到系统的所有类中扩展,但是定义Nothing为子类型的相关性仅限于与子类型相关的所有位置。

这里重要的一点是,不存在type的实例Nothing,因此,对它的处理严格限于类型检查,这在编译器领域都是如此。


2
我仍然不明白这是怎么做的...请参阅我的问题的编辑
vainolo 2013年

1
“将“无”定义为子类型的相关性仅限于与子类型相关的所有地方。” 您想传达什么?X相关X在哪里相关?
phant0m 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.