Artykuł w Wikipedii na temat języków opartych na prototypach zawiera następujący akapit:
Prawie wszystkie systemy oparte na prototypach są oparte na językach interpretowanych i dynamicznie typowanych. Systemy oparte na statycznie typowanych językach są jednak technicznie wykonalne.
W jaki sposób system typów statycznych nakłada ograniczenia lub wprowadza złożoność w języku opartym na prototypach i dlaczego istnieją bardziej dynamiczne typy prototypowe?
Odpowiedzi:
Granica między typem podstawowym a obiektem jest rozmyta i często sztucznie wprowadzana. Na przykład w C struktura jest tylko zbiorem rekordów, tylko pochodnym typem nieobiektywnym. W C ++ struct to klasa ze wszystkimi polami publicznymi, obiekt. Mimo to C ++ jest prawie całkowicie wstecznie kompatybilny z C ... granica jest tutaj naprawdę miękka.
W przypadku programowania opartego na prototypach obiekty muszą być modyfikowalne w czasie wykonywania. MUSZĄ być pisane na maszynie, ponieważ każda zmienia się w czasie wykonywania, klasa jednego rodzaju zmienia się w inny - zmienia się jej typ.
Możesz jednak zachować podstawowe i pochodne typy niebędące obiektami jako statyczne. Ale wprowadza to dziwną rozbieżność, obiekty są pisane na miękko, obiekty inne są pisane statycznie, a między nimi należy ustalić twardą barierę. Czy powinieneś być w stanie przekształcić strukturę? Sznurek? Czy liczba powinna być klasą, typem podstawowym, czy zestawem typów podstawowych, int / float / bignum / itp.?
To jest bardziej naturalne i łatwiejsze do nauczenia się, używania i pisania, aby mieć ten jednolity, wszystkie typy są zmienne lub żadne typy nie są zmienne w czasie wykonywania. Jeśli zadeklarujesz, że tylko jeden typ (obiekt) jest mutowalny, możesz spotkać się z bólami głowy i problemami obu światów.
Typy statyczne to:
Typ dynamiczny to:
Mieszając te dwa, poświęcasz dużo.
źródło
Trudność jest dość prosta: Patrząc na obiekty jako słowniki metod lub rzeczy reagujące na komunikaty, przestrzegaj następujących zasad dotyczących typowych języków OO:
Wszystkie klucze / komunikaty słownika są zazwyczaj deklarowane z góry, przy użyciu statystycznie zadeklarowanych identyfikatorów.
Niektóre zestawy komunikatów są deklarowane z wyprzedzeniem, a obiekty są powiązane z tymi zestawami w celu ustalenia, na które komunikaty odpowiadają.
Relacje włączenia jednego zestawu komunikatów będących podzbiorem innego są deklarowane statycznie i wyraźnie; niezadeklarowane, ale podzbiory logiczne są nieprawidłowe.
Sprawdzanie typu próbuje zapewnić, że wszystkie wiadomości są wysyłane tylko do obiektów, które na nie odpowiadają.
Każdy z tych konfliktów w pewnym stopniu koliduje z systemem opartym na prototypach:
Nazwy wiadomości mogą być zadeklarowane z wyprzedzeniem, w postaci „atomów” lub ciągów wewnętrznych lub czegokolwiek, ale niewiele więcej; plastyczność obiektów oznacza, że przypisywanie typów do metod jest niewygodne.
Prawdopodobnie jest to podstawowa cecha systemu opartego na prototypach, polegająca na tym, że zestawy komunikatów są definiowane przez reakcję obiektu, a nie na odwrót. Rozsądne byłoby przypisywanie aliasów do poszczególnych kombinacji w czasie kompilacji, ale zestawy komunikatów określone w czasie wykonywania muszą być możliwe.
Rzeczywisty wpływ dwóch powyższych trafia do domu z relacjami włączenia, w których wyraźne deklaracje są całkowicie niewykonalne. Dziedziczenie w sensie statycznego, nominalnego podtypu jest przeciwne do systemu opartego na prototypach.
To prowadzi nas do ostatniego punktu, którego tak naprawdę nie chcemy zmieniać. Nadal chcielibyśmy zapewnić, aby wiadomości były wysyłane tylko do obiektów, które na nie odpowiadają. Jednak:
Jak więc można to obejść? Albo w jakiś sposób ogranicz całą ogólność (co jest nieprzyjemne i może szybko zniszczyć wszelkie korzyści wynikające z użycia systemu opartego na prototypach), albo spraw, aby system pisma był bardziej płynny i wyrażał ograniczenia, a nie dokładne typy .
System typów oparty na ograniczeniach szybko prowadzi do pojęcia strukturalnego podtytułu , które w bardzo luźnym sensie można uznać za statyczny odpowiednik „typowania kaczego”. Największymi przeszkodami są tutaj to, że takie systemy są znacznie bardziej skomplikowane w sprawdzaniu typu i są mniej znane (co oznacza niewiele wcześniejszej pracy do nauki).
Podsumowując: Jest to możliwe, jest to po prostu trudniejsze niż system o nominalnym typie statycznym lub system dynamiczny oparty na metadanych środowiska wykonawczego, a zatem mało osób się tym przejmuje.
źródło
Uważam, że sposobem na osiągnięcie statycznie typowanego języka opartego na prototypach byłoby oparcie go na szablonach i koncepcjach.
Pojęcia były kiedyś planowaną funkcją dla C ++ 0x. Kod ogólny w szablonach C ++ jest już de facto „statycznie zapisywany”. Ideą Pojęć jest możliwość powiedzenia pewnych rzeczy na temat wymaganych elementów i charakterystyk typów, bez wymagania lub sugerowania modelu dziedziczenia klas leżącego u podstaw tej relacji (ponieważ musiał współpracować z istniejącym kodem szablonu, który był już „statycznie zapisany” ).
W języku opartym od podstaw na szablonach i pojęciach koncepcje będą oparte na prototypach, a szablony uwolnią cię od dbania o dowolny model klasy, który może, ale nie musi być użyty do implementacji typów wartości.
Oprócz sztuczek polegających na stosowaniu kompilacji etapowej, aby język mógł być własnym metajęzykiem, te prototypowe pochodne Pojęć z konieczności byłyby niezmienne po utworzeniu. Jednak zarzut, że nie jest oparty na prototypie, to czerwony śledź. Byłby to po prostu język funkcjonalny. Przynajmniej próbowano zastosować dynamiczny język bazowy prototypów, który jest również funkcjonalny .
źródło