Як нічого не є підтипом усіх інших типів у Scala


19

Я беру курс курсу Мартіна Одерського з функціонального програмування зі шкалою, і поки що я засвоїв дві речі, які разом не мають сенсу:

  1. Scala не підтримує багаторазове успадкування
  2. Nothing є підтипом будь-якого іншого типу

Ці два твердження не можуть жити разом, так як саме це робиться? і що саме означає "підтип будь-якого іншого типу"

Редагуйте 1

В API Scala , Nothingвизначається як abstract final class Nothing extends Any... так як він може поширюватися на інші класи?


Ця сторінка може трохи допомогти: artima.com/pins1ed/scalas-hierarchy.html
jhewlett

Наскільки я можу бачити , що це визначається як «кінцева риса Ніщо не проходить Будь» scala-lang.org/api/2.7.6/scala/Nothing.html
Den

8
Ви плутаєте типи та класи. Ці дві речі дуже різні. На жаль, ви не єдиний, хто збентежений цієї відмінності, і в самому справі , до жаль, деякі з тих , кого бентежить трапляється конструктори популярних мов , таких як Java, C # і C ++. Це не говорить про те, що Nothingце підклас кожного іншого класу. Це говорить про те, що це підтип кожного іншого типу .
Йорг W Міттаг

1
@delnan: інтерфейси Java взяті безпосередньо з протоколів Smalltalk. У Smalltalk типи є лише протоколами, класи - ні. У Java і інтерфейси, і класи - це типи. Це неправильно. Класи не типи, є лише інтерфейси. Те, що в усіх цих мовах є речі, які є типами, а не класами, не має значення. Проблема полягає в тому, що в цих мовах класи - це типи, що неправильно.
Йорг W Міттаг

1
@ JörgWMittag Це інше твердження і надзвичайно сперечається (я схильний погоджуватися, що це шкідливо, але я б не пов'язував це з нерозумінням введення тексту). Тут немає сенсу обговорювати це.

Відповіді:


27

Підтипізація та успадкування - це дві різні речі! Nothingне розширює все, це підтип , він лише розширюється Any.

Специфікація [§3.5.2] має особливий випадок , який регулює подтіпірованія-відносини Nothing:

§3.5.2 Відповідність

  • [...]
  • Для кожного типу значень
    T,scala.Nothing <: T <:scala.Any
  • Для кожного конструктора типів T(з будь-якою кількістю параметрів типу)
    scala.Nothing <: T <: scala.Any
  • [...]

Де в <:основному означає "є підтипом".

Щодо того, як це робиться. Ми не знаємо, це магія компілятора та деталізація щодо реалізації.

Досить часто мова робить те, що ви як програміст не можете. Як відповідне Nothing: Все у Скалі успадковує Any, окрім всього Any. Чому Anyвід чогось не успадковується? Ви не можете цього зробити. Чому Скала може це зробити? Ну, тому що Скала встановив правила, а не ти. Nothingбути підтипом всього - це лише інший приклад цього.


10
BTW: це точно те ж саме, nullщо можна призначити для поля будь-якого типу на Java. Чому це можливо? Чи nullє примірник кожного класу? Ні, це можливо, тому що компілятор так говорить. Період.
Йорг W Міттаг

8
Якби я міг стовідсотково підтримати це, я би. Плутати типи та класи - це одна з найгірших речей мов, таких як Java.
Йорг W Міттаг

1
Для допитливих душ про різницю між спадщиною та підтипами cmi.ac.in/~madhavan/courses/pl2006/lecturenotes/lecture-notes/… однак я не купую її - якщо ви успадковуєте (як extendsу Java, а не як складати ) ти все-таки робиш це для підтипу.
greenoldman

11

Коли він каже, що Скала не підтримує багатократне успадкування, то він посилається на успадкування реалізації методу кілька разів. Звичайно, ви можете реалізувати декілька інтерфейсів / ознак у класі, і вони можуть навіть визначити один і той же метод, але у вас не виникає конфлікт між різними реалізаціями через лінеаризацію ознак.

Загалом, якщо у вас є клас C1із методом, f()а клас C2також із методом f(), то множинне успадкування означає, що ви можете якось успадкувати обидві реалізації f(). Це може призвести до різних проблем, які Скала вирішує, лише дозволяючи вам успадковувати з одного класу, а у випадку декількох ознак, вибираючи одну реалізацію на основі порядку ознак.

Що стосується Nothingсправді просто, тому що нічого не визначено атрибутами чи методами. Таким чином, у вас не може бути конфліктів щодо спадщини. Але я припускаю, що більшість ваших сюрпризів відбувається від іншого розуміння багаторазового успадкування.

Після того, як ви зрозумієте, що лінеаризація ознак ефективно усуває будь-яку неоднозначність спадкування, і що ми не називаємо спадкування з декількох ознак як множинне успадкування через це, то вам слід добре.

Щодо того, як це реалізується: компілятор, зрештою, відповідає за це. Див. Розділ 3.5.2 специфікації мови Scala , який серед інших властивостей включає:

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

Або іншими словами, якщо ви хочете правильно реалізувати компілятор, він повинен обробляти Nothingяк підтип всього за специфікацією. З очевидних причин Nothingне визначено, щоб поширюватися на всі класи, завантажені в систему, але релевантність визначення Nothingяк підтипу обмежена всіма місцями, де підтипування має значення.

Важливим моментом тут є те, що не існує жодного примірника типу Nothing, отже, його обробка суворо обмежена перевіркою типу, що є всіма у сфері компілятора.


2
Я все ще не розумію, як це робиться ... Дивіться правки мого запитання
vainolo

1
"релевантність визначення Нічого як підтипу обмежена всіма місцями, де підтипування має значення." Що ви хочете з цим передати? X релевантний, де X доречний?
phant0m
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.