Comment rien n'est un sous-type de tous les autres types dans Scala

19

Je prends le cours de Martin Odersky sur la programmation fonctionnelle avec scala, et pour l'instant j'ai appris deux choses qui ensemble n'ont pas de sens:

  1. Scala ne prend pas en charge l'héritage multiple
  2. Nothing est un sous-type de tous les autres types

Ces deux déclarations ne peuvent pas cohabiter, alors comment cela se fait-il exactement? et quelle est exactement la signification de "sous-type de tout autre type"

Modifier 1

Dans l' API Scala , Nothingest défini comme abstract final class Nothing extends Any... alors comment peut-il étendre d'autres classes?

vainolo
la source
Cette page pourrait vous aider un peu: artima.com/pins1ed/scalas-hierarchy.html
jhewlett
Pour autant que je puisse le voir, il est défini comme "trait final, rien ne s'étend" scala-lang.org/api/2.7.6/scala/Nothing.html
Den
8
Vous confondez types et classes. Ces deux choses sont très différentes. Malheureusement, vous n'êtes pas le seul à être confus par cette distinction, et vraiment, malheureusement, certains de ceux qui sont confus se trouvent être les concepteurs de langages populaires comme Java, C # et C ++. Il ne dit pas que Nothingc'est une sous-classe de toutes les autres classes. Il dit que c'est un sous - type de tous les autres types .
Jörg W Mittag
1
@delnan: Les interfaces de Java sont directement extraites des protocoles de Smalltalk. Dans Smalltalk, seuls les protocoles sont des types, les classes ne le sont pas. En Java, les interfaces et les classes sont des types. C'est faux. Les classes ne sont pas des types, seules les interfaces le sont. Le fait que toutes ces langues aient des choses qui sont des types et non des classes est sans importance. Le problème est que dans ces langues, les classes sont des types, ce qui est faux.
Jörg W Mittag
1
@ JörgWMittag C'est une déclaration différente, et extrêmement discutable (j'ai tendance à convenir que c'est dangereux, mais je n'attribuerais pas cela à une mauvaise compréhension de la frappe). Inutile d'en discuter ici.

Réponses:

27

Le sous-typage et l'héritage sont deux choses différentes! Nothingne prolonge pas tout, c'est un sous - type , il ne fait que s'étendre Any.

La spécification [§3.5.2] a un cas particulier régissant la relation de sous-typage de Nothing:

§3.5.2 Conformité

  • [...]
  • Pour chaque type de valeur
    T,scala.Nothing <: T <:scala.Any
  • Pour chaque constructeur de type T(avec un nombre quelconque de paramètres de type)
    scala.Nothing <: T <: scala.Any
  • [...]

<:signifie essentiellement "est un sous-type de".

Quant à la façon dont cela est fait: nous ne savons pas, c'est la magie du compilateur et un détail d'implémentation.

Très souvent, un langage fait des choses que vous ne pouvez pas faire en tant que programmeur. En contrepartie de Nothing: Tout en Scala hérite de Anytout sauf Any . Pourquoi Anyn'hérite- t-il pas de quelque chose? Tu ne peux pas faire ça. Pourquoi Scala peut-il faire ça? Eh bien, parce que Scala a établi les règles, pas vous. Nothingêtre un sous-type de tout n'est qu'un autre exemple de cela.

phant0m
la source
10
BTW: c'est exactement la même chose nullqu'être assignable à un champ de chaque type en Java. Pourquoi est-ce possible? Est nullune instance de chaque classe? Non, c'est possible car le compilateur le dit. Période.
Jörg W Mittag
8
Si je pouvais voter contre cela cent fois, je le ferais. La confusion des types et des classes est l'une des pires choses que les langages comme Java nous ont apporté.
Jörg W Mittag
1
Pour les âmes curieuses à propos de la différence entre l'héritage et les sous-types cmi.ac.in/~madhavan/courses/pl2006/lecturenotes/lecture-notes/… cependant je ne l'achète pas - si vous héritez (comme extendsen Java, et pas en tant que compose) ) vous le faites pour le sous-typage après tout.
greenoldman
11

Lorsqu'il dit que Scala ne prend pas en charge l'héritage multiple, il fait référence à l'héritage d'une implémentation de méthode plusieurs fois. Bien sûr, vous pouvez implémenter plusieurs interfaces / traits dans une classe, et ils peuvent même définir la même méthode, mais vous n'obtenez pas de conflit entre les différentes implémentations en raison de la linéarisation des traits.

En général, si vous avez une classe C1avec une méthode f()et une classe C2également avec une méthode f(), l'héritage multiple signifie que vous pouvez en quelque sorte hériter des deux implémentations de f(). Cela peut entraîner divers problèmes, que Scala résout en ne vous laissant hériter que d'une seule classe et en cas de traits multiples en sélectionnant une implémentation en fonction de l'ordre des traits.

Quant aux Nothingchoses sont vraiment simples, car rien n'a d'attributs ou de méthodes définis. Vous ne pouvez donc pas avoir de conflits d'héritage. Mais je suppose que la majeure partie de votre surprise vient d'une compréhension différente de l'héritage multiple.

Une fois que vous comprenez que la linéarisation des traits élimine efficacement toute ambiguïté de l'héritage, et que nous ne faisons pas référence à l'héritage de plusieurs traits comme étant un héritage multiple à cause de cela, alors tout va bien.

Quant à la façon dont cela est réalisé: le compilateur est finalement responsable de cela. Voir la conformité à la spécification 3.5.2 du langage Scala , qui comprend, entre autres propriétés:

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

Ou en d'autres termes, si vous voulez implémenter un compilateur correctement, il doit le gérer Nothingcomme un sous-type de tout par spécification. Pour des raisons évidentes, il Nothingn'est pas défini pour s'étendre à toutes les classes chargées dans le système, mais la pertinence de la définition en Nothingtant que sous-type est limitée à tous les endroits où le sous-typage est pertinent.

Un point important ici est qu'il n'existe aucune instance de type Nothing, par conséquent, son traitement est strictement limité à la vérification de type, qui est entièrement du domaine du compilateur.

Franc
la source
2
Ce que je ne comprends toujours pas, c'est comment cela se fait ... Voir la modification de ma question
vainolo
1
"la pertinence de définir Nothing comme sous-type est limitée à tous les endroits où le sous-typage est pertinent." Que voulez-vous transmettre avec cela? X est pertinent lorsque X est pertinent?
phant0m