Czym dziedziczenie różni się od podtypu?

15

W perspektywie języka programowania, co oznacza podtyp? Słyszałem, że „Dziedziczenie nie jest poddziałem”. Jakie są zatem różnice między dziedziczeniem a poddziałem?

RoboAlex
źródło
6
Zastanawiam się, czy to pytanie (i inne podobne) może zostać przekierowane na nową stronę cs.SE, kiedy wejdzie w publiczną wersję beta?
Suresh Venkat,
1
Witamy w cstheory, witrynie pytań i odpowiedzi na pytania na poziomie badawczym w teoretycznej informatyce (TCS). Twoje pytanie nie wydaje się być pytaniem na poziomie badawczym w TCS. Zapoznaj się z często zadawanymi pytaniami, aby uzyskać więcej informacji o tym, co to oznacza, oraz sugestie dotyczące witryn, które mogą przyjąć Twoje pytanie. Na koniec, jeśli twoje pytanie jest zamknięte z powodu jego braku i uważasz, że możesz je edytować, aby stało się pytaniem na poziomie badawczym, możesz to zrobić. Zamknięcie nie jest trwałe i pytania można ponownie otworzyć, sprawdź FAQ w celu uzyskania dalszych informacji.
Kaveh
3
@UdayReddy: Żadne pytanie nie było trywialne, kiedy po raz pierwszy odpowiedziałem, ale powinniśmy podjąć decyzję z nowoczesnego punktu widzenia. Ten sam argument, co twój, sugerowałby, że pytanie o algorytm Dijkstry jest tematem, ponieważ pierwszy artykuł mówi o tym i nic więcej.
Tsuyoshi Ito,
3
@TsuyoshiIto Analogia nie jest właściwa, ponieważ pierwsza praca Dijkstry rozwiązała problem, podczas gdy pierwsza praca Cardelli tutaj stworzyła problem. Mimo to uważam, że nie mierzymy stanu techniki na podstawie pierwszego artykułu. Zapewniam cię, że różnice między dziedziczeniem a podliczaniem nie stanowią rozwiązanego problemu, i spodziewam się, że kwestia ta będzie omawiana przynajmniej przez kolejne 20 lat. Pytającemu można doradzić wykonanie dodatkowej pracy domowej i edycję pytania w celu wyjaśnienia problemów na poziomie badawczym.
Uday Reddy,
3
W każdym razie łatwo jest wskazać OP na dokument Cooka i wsp. O tej samej nazwie: citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.102.8635
Andreas Rossberg

Odpowiedzi:

18

[Nie zastanawiałem się głęboko nad zagadnieniami systemów typu obiektowego, ale powiem, co wiem, aby rozpocząć dyskusję.]

Mówimy, że jest podtypem B, jeśli wszystkie wartości typu A mogą być użyte w każdym kontekście, w którym oczekiwane są wartości typu B. Lub, mówiąc inaczej, -typed wartości mogą „maskarada” jako B -typed wartości.ZAbZAbZAb

Jeśli taka maskarada nie stwarza problemów z sprawdzaniem typu, tj Podłączanie wartości typu A, gdzie potrzebne są wartości typu B , nadal sprawdza typ, nazywamy to „podtypem strukturalnym” . Jeśli nie powoduje problemów z zachowaniem, tj. Takie podłączenie nie zmienia oczekiwanego zachowania, wówczas nazywamy to „podtypem behawioralnym” . („Oczekiwane zachowanie” będzie musiało zostać osobno sformalizowane i możliwe jest wiele koncepcji zachowania).ZAb

Podtypowanie strukturalne nie zapewnia podtypowania behawioralnego, ponieważ struktura typu może pasować z przyczyn przypadkowych. Jednak zdefiniowanie oczekiwanego zachowania nie jest łatwe. Tak więc wiele języków programowania wykorzystuje punkt pośredni, w którym użytkownik musi zadeklarować, który typ jest podtypem. Jest to określane jako „podtyp nominalny” . Zobacz pytanie o ukryte podtytułydo dyskusji na ten temat. Chodzi o to, że programista musi zapewnić podtypowanie behawioralne dla wszystkich zadeklarowanych podtypów z wykorzystaniem własnej pomysłowości. Język nie może zaoferować żadnej pomocy. Jednak wszystkie zadeklarowane podtypy muszą być co najmniej podtypami strukturalnymi. W przeciwnym razie program nie mógłby wpisać sprawdzania. Język może to zapewnić. (Niektóre języki programowania nie mają wystarczająco dobrych systemów typów, aby zapewnić to w czasie kompilacji. Jeśli tak, awaria typu zostanie wykryta w czasie wykonywania lub być może zostaną wygenerowane błędne wyniki. Takie dziury są oczywiście niepożądane).

Kiedy definiuje się podklasy w programach obiektowych, zwykle dodaje się publicznie widoczne pola (lub metody). W większości języków programowania takie podklasy są uważane za podtypy nominalne . Pytanie brzmi, czy są to również podtypy strukturalne . Jeśli nie są, tzn. Język programowania pozwala zadeklarować nominalne podtypy, które nie są podtypami strukturalnymi, wówczas w języku programowania pojawią się dziury.

W prostych przypadkach dodawanie pól działa poprawnie. Typ nadklasy wymaga mniejszej liczby pól niż typ podklasy. Tak więc, jeśli podłączysz instancję podklasy, w której spodziewana jest instancja klasy sueprclass, program po prostu zignoruje podane dodatkowe pola i nic nie pójdzie źle.

Jeśli jednak nadklasa lub podklasa ma metody, które pobierają argumenty tego samego typu co ona sama lub zwracają wyniki tego samego typu co ona sama, pojawiają się problemy. Zatem typ interfejsu podklasy nie jest podtypem strukturalnym tego podklasy . Powszechnie używane bezpieczne języki programowania, takie jak Java, nie pozwalają na takie podklasy. Tak, one ograniczać się języka w celu uzyskania bezpieczeństwa typu. Mówi się, że język programowania Eiffel poświęcił bezpieczeństwo typu, aby zamiast tego uzyskać elastyczność . Jeśli ktoś projektuje silny system typów zachowujący elastyczność, musi zrezygnować z zasady, że podklasy powodują powstanie podtypów. Stąd tytuł pracy „Dziedziczenie nie jest poddziałem”. Autorzy proponują inne pojęcie podtypu wyższego rzędu, które działa zamiast tego. Kim Bruce ma również ściśle powiązaną propozycję zwaną „dopasowywaniem”, która osiąga ten sam efekt. Zobacz tę prezentację . Pomocny jest także dokument przedstawiający stanowisko Andrew Blacka.

Społeczność semantyki prawdopodobnie ponosi winę za to, że w dużej mierze ignoruje problem. Tradycyjnie uważaliśmy to za praktyczne zagadnienie inżynieryjne typu systemu, które nie ma teoretycznego zainteresowania. Jeśli tak nie jest i rzeczywiście istnieje w tej dziedzinie trochę semantyki, mam nadzieję, że inni o tym wspomną.

Uday Reddy
źródło
1
Być może warto również wspomnieć, że istnieją języki, które skutecznie oddzieliły podtypowanie od dziedziczenia, np. Ocaml w swoim systemie obiektowym.
Andreas Rossberg,
@AndreasRossberg Rzeczywiście, OCaml nie był w mojej ramce, kiedy napisałem tę odpowiedź. Podejrzewam, że OCaml w ogóle nie ma nominalnego podtypu. Dlatego niektóre z tych problemów nie powstałyby. Istnieje jednak możliwość, że typy mogą przypadkowo pasować, nawet jeśli zachowanie się nie zgadza, a system typów nie będzie w stanie pomóc w wykrywaniu tego rodzaju błędów.
Uday Reddy,