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:
- Scala ne prend pas en charge l'héritage multiple
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 , Nothing
est défini comme abstract final class Nothing extends Any
... alors comment peut-il étendre d'autres classes?
programming-languages
scala
vainolo
la source
la source
Nothing
c'est une sous-classe de toutes les autres classes. Il dit que c'est un sous - type de tous les autres types .Réponses:
Le sous-typage et l'héritage sont deux choses différentes!
Nothing
ne prolonge pas tout, c'est un sous - type , il ne fait que s'étendreAny
.La spécification [§3.5.2] a un cas particulier régissant la relation de sous-typage de
Nothing
:Où
<:
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 deAny
tout saufAny
. PourquoiAny
n'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.la source
null
qu'être assignable à un champ de chaque type en Java. Pourquoi est-ce possible? Estnull
une instance de chaque classe? Non, c'est possible car le compilateur le dit. Période.extends
en Java, et pas en tant que compose) ) vous le faites pour le sous-typage après tout.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
C1
avec une méthodef()
et une classeC2
également avec une méthodef()
, l'héritage multiple signifie que vous pouvez en quelque sorte hériter des deux implémentations def()
. 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
Nothing
choses 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:
Ou en d'autres termes, si vous voulez implémenter un compilateur correctement, il doit le gérer
Nothing
comme un sous-type de tout par spécification. Pour des raisons évidentes, ilNothing
n'est pas défini pour s'étendre à toutes les classes chargées dans le système, mais la pertinence de la définition enNothing
tant 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.la source