Wie ist Nothing ein Untertyp von jedem anderen Typ in Scala

19

Ich nehme an Martin Oderskys Kurs über funktionale Programmierung mit scala teil und habe im Moment zwei Dinge gelernt, die zusammen keinen Sinn ergeben:

  1. Scala unterstützt keine Mehrfachvererbung
  2. Nothing ist ein Subtyp von jedem anderen Typ

Diese beiden Aussagen können nicht zusammenleben. Wie genau geschieht das? und was genau ist die Bedeutung von "Untertyp von jedem anderen Typ"

Bearbeiten 1

In der Scala API , Nothingist definiert als abstract final class Nothing extends Any... so wie es andere Klassen erweitern?

vainolo
quelle
Diese Seite könnte ein bisschen helfen: artima.com/pins1ed/scalas-hierarchy.html
jhewlett
Soweit ich sehen kann, wird es als "letzte Eigenschaft, die nichts erweitert" definiert. Scala-lang.org/api/2.7.6/scala/Nothing.html
Den
8
Sie verwirren Typen und Klassen. Diese beiden sind sehr verschiedene Dinge. Leider sind Sie nicht der einzige, der von dieser Unterscheidung verwirrt ist, und wirklich, leider sind einige derjenigen, die verwirrt sind, Designer von populären Sprachen wie Java, C # und C ++. Es heißt nicht, dass dies Nothingeine Unterklasse jeder anderen Klasse ist. Es sagt, dass es ein Subtyp von jedem anderen Typ ist .
Jörg W Mittag
1
@delnan: Javas Schnittstellen werden direkt von Smalltalks Protokollen übernommen. In Smalltalk sind nur Protokolle Typen, Klassen nicht. In Java sind sowohl Interfaces als auch Klassen Typen. Das ist falsch. Klassen sind keine Typen, nur Schnittstellen. Die Tatsache, dass alle diese Sprachen Dinge haben, die Typen und keine Klassen sind, ist irrelevant. Das Problem ist, dass Klassen in diesen Sprachen Typen sind, was falsch ist.
Jörg W Mittag
1
@ JörgWMittag Das ist eine andere Aussage und äußerst umstritten (ich stimme eher zu, dass sie schädlich ist, aber ich würde dies nicht auf ein Missverständnis beim Tippen zurückführen). Es macht keinen Sinn, hier darüber zu diskutieren.

Antworten:

27

Subtypisierung und Vererbung sind zwei verschiedene Dinge! ErweitertNothing nicht alles, es ist ein Subtyp , es erweitert nur .Any

Die Spezifikation [§3.5.2] hat einen Sonderfall, der die Subtypisierungsbeziehung regelt von Nothing:

§3.5.2 Konformität

  • [...]
  • Für jeden Werttyp
    T,scala.Nothing <: T <:scala.Any
  • Für jeden Typkonstruktor T(mit beliebig vielen Typparametern)
    scala.Nothing <: T <: scala.Any
  • [...]

Wobei im <:Grunde bedeutet "ist ein Subtyp von".

Wie das gemacht wird: Wir wissen nicht, es ist die Magie des Compilers und ein Implementierungsdetail.

Sehr oft macht eine Sprache Dinge, die Sie als Programmierer nicht können. Als Gegenstück zu Nothing: Alles in Scala erbt von Any, alles außer Any . Warum Anyerbt nicht von etwas? Das kannst du nicht machen. Warum kann Scala das? Nun, weil Scala die Regeln festgelegt hat, nicht Sie. Nothingein Subtyp von allem zu sein, ist nur ein weiteres Beispiel dafür.

phant0m
quelle
10
Übrigens: Dies ist genau das Gleiche wie nulldie Zuweisung zu einem Feld jedes Typs in Java. Warum ist das möglich? Ist nulleine Instanz jeder Klasse? Nein, es ist möglich, weil der Compiler dies sagt. Zeitraum.
Jörg W Mittag
8
Wenn ich das hundertmal unterstützen könnte, würde ich es tun. Verwirrende Typen und Klassen sind eines der schlimmsten Dinge, die Sprachen wie Java auf uns gebracht haben.
Jörg W Mittag
1
Für neugierige Seelen über den Unterschied zwischen Vererbung und Subtypen kaufe ich es jedoch nicht - wenn Sie es erben (wie extendsin Java und nicht so komponieren) ) Sie tun es doch für die Subtypisierung.
Greenoldman
11

Wenn er sagt, dass Scala die Mehrfachvererbung nicht unterstützt, bezieht er sich darauf, eine Methodenimplementierung mehrmals zu erben. Natürlich können Sie mehrere Interfaces / Merkmale in einer Klasse implementieren, und sie können sogar dieselbe Methode definieren, aber Sie erhalten keinen Konflikt zwischen den verschiedenen Implementierungen aufgrund der Merkmallinearisierung.

Wenn Sie eine Klasse C1mit einer Methode f()und eine Klasse C2auch mit einer Methode haben f(), bedeutet Mehrfachvererbung im Allgemeinen, dass Sie beide Implementierungen von irgendwie erben können f(). Dies kann zu verschiedenen Problemen führen, die Scala dadurch löst, dass Sie nur von einer einzelnen Klasse erben lassen und bei mehreren Merkmalen eine Implementierung anhand der Reihenfolge der Merkmale auswählen.

Was Nothingsind die Dinge wirklich einfach, weil nichts definiert keine Attribute oder Methoden hat. Sie können also keine Vererbungskonflikte haben. Aber ich gehe davon aus, dass der größte Teil Ihrer Überraschung auf einem anderen Verständnis der Mehrfachvererbung beruht.

Wenn Sie verstanden haben, dass die Linearisierung von Merkmalen die Mehrdeutigkeit der Vererbung effektiv beseitigt und wir das Erben von mehreren Merkmalen aus diesem Grund nicht als Mehrfachvererbung bezeichnen , sollten Sie in Ordnung sein.

Wie dies realisiert wird: Der Compiler ist letztendlich dafür verantwortlich. Weitere Informationen finden Sie in der Scala-Sprachspezifikation in Abschnitt 3.5.2, der unter anderem Folgendes enthält:

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

Mit anderen Worten, wenn Sie einen Compiler korrekt implementieren möchten, muss er nach NothingSpezifikation als Subtyp von allem behandelt werden. Aus offensichtlichen Gründen Nothinggilt die Definition nicht für alle in das System geladenen Klassen. Die Relevanz der Definition Nothingals Untertyp ist jedoch auf alle Stellen beschränkt, an denen die Untertypisierung relevant ist.

Ein wichtiger Punkt hierbei ist, dass es keine Instanz eines Typs Nothinggibt. Daher ist seine Behandlung streng auf die Typprüfung beschränkt, die sich ausschließlich im Bereich des Compilers befindet.

Frank
quelle
2
Was ich immer noch nicht verstehe, ist, wie das gemacht wird ... Siehe die Bearbeitung meiner Frage
vainolo
1
"Die Relevanz der Definition von Nothing als Untertyp ist auf alle Stellen beschränkt, an denen die Untertypisierung relevant ist." Was willst du damit vermitteln? X ist relevant, wo X relevant ist?
Phant0m