Jaki jest nieskomplikowany przykład statycznego sprawdzania typu, który jest zbyt konserwatywny?


9

W Concepts in Programming Languages John Mitchell pisze, że statyczne sprawdzanie typów jest z konieczności konserwatywne (zbyt surowe) z powodu problemu zatrzymania. Podaje jako przykład:

if (complicated-expression-that-could-run-forever)
   then (expression-with-type-error)
   else (expression-with-type-error)

Czy ktoś może udzielić nieskomplikowanej odpowiedzi, która naprawdę byłaby kwestią praktyczną?

Rozumiem, że Java zezwala na dynamicznie sprawdzane rzutowania dla takich przypadków:

if (foo instanceof Person) {
    Person p = (Person) foo;
    :
}

ale uważam, że jest to raczej niedobór języka / kompilatora Java niż problem międzyjęzykowy.


2
Podany przykład Javy jest nieskomplikowanym przykładem statycznego sprawdzania typu, który jest zbyt konserwatywny. Mówiąc inaczej: odpowiedź zależy od tego, jaki system typów masz na myśli. Dla każdego przykładu, który wymyślimy, zawsze będzie system typów, który poradzi sobie z tym przykładem (system typów nie jest zbyt konserwatywny na tym przykładzie). Dla każdego typu systemu zawsze możemy znaleźć przykład, w którym jest on zbyt konserwatywny. Myślę więc, że musisz określić system typów. Jeśli system typów Java nie jest tym, o czym myślałeś, czy jest coś bardziej szczegółowego, o czym myślałeś? Wnioskowanie o typie ML?
DW

można argumentować, że przykładem jest statyczna analiza kodu „zachowawcza”, a nie sprawdzanie typów. pomocne byłoby zdefiniowanie „konserwatywnego” . prawdopodobnie wszystkie systemy typu statycznego będą „konserwatywne” w porównaniu do systemów dynamicznych, ponieważ te pierwsze są z definicji bardziej rygorystyczne w czasie kompilacji . jednak można argumentować, że żadne z nich nie jest bardziej rygorystyczne w czasie wykonywania, ponieważ sprawdzanie dynamiczne może również zwracać podobne błędy (oparte na typach). a przy okazji, dynamiczne sprawdzanie rzutów w językach uruchomieniowych w językach nie jest wadą , są one w większości statycznie sprawdzanych językach, być może gdzie indziej możliwe.
vzn

Odpowiedzi:


7

Zawsze uważałem to bardziej za wygodę niż za to, czy algorytm może być wyrażony w ogóle, czy nie. Gdybym naprawdę chciał uruchamiać programy takie jak ten stworzony przez Mitchella, po prostu napisałbym odpowiedni symulator maszyny Turinga w moim statycznie pisanym języku.

Sztuczka z systemem typu statycznego polega na zapewnieniu odpowiedniego rodzaju elastyczności tylko w przypadkach, w których elastyczność umożliwia pisanie kodu, który jest łatwiejszy w utrzymaniu.

Oto kilka przykładów technik strukturyzacji programów, które czasami uważa się za łatwiejsze do zarządzania w dynamicznych językach niż w przypadku języków o typie statycznym.

Leki ogólne i pojemniki

W językach o typie statycznym przed ML (ok. 1973) i CLU (ok. 1974) nie było trudno stworzyć czerwono-czarne drzewo ciągów, czerwono-czarne drzewo liczb całkowitych, czerwono-czarne drzewo liczb zmiennoprzecinkowych lub czerwono-czarne drzewo elementów określonego typu Foo. Utworzenie pojedynczej implementacji czerwono-czarnego drzewa było jednak trudne (a może niemożliwe), które było zarówno sprawdzane statycznie, jak i mogło obsługiwać dowolny z tych typów danych. Rozwiązaniem problemu było (1) całkowite wyrwanie się z systemu typów (na przykład: za pomocąvoid * w C), (2), aby napisać sobie jakiś preprocesor makr, a następnie napisać makra, które wytwarzają kod dla każdego określonego typu, którego chcesz, lub (3) użyj podejścia Lisp / Smalltalk (i Java) sprawdzania typu wyodrębnionego obiekt dynamicznie.

ML i CLU wprowadziły pojęcie odpowiednio wywnioskowanych i jawnie zadeklarowanych (statycznych) sparametryzowanych typów, które pozwalają pisać ogólne, statycznie typowane typy kontenerów.

Polimorfizm podtypu

W językach o typie statycznym przed Simula67 (ok. 1967) i Hope (ok. 1977) nie było możliwe zarówno dynamiczne wysyłanie, jak i statyczne sprawdzanie, czy uwzględniono przypadek dla każdego podtypu. Wiele języków miał jakąś formę rekord z wariantami , ale było to w gestii programisty, aby upewnić się, że ich caselub switchoświadczenia, lub ich stoły skoku, pokryty każdą możliwą tag.

Języki zgodne z modelem Simula (C ++, Java, C #, Eiffel) zapewniają klasy abstrakcyjne z podklasami, w których kompilator może sprawdzić, czy każda podklasa zaimplementowała wszystkie metody zadeklarowane przez klasę nadrzędną. Języki zgodne z modelem Hope (wszystkie warianty ML, od SML / NJ do Haskell) mają algebraiczne podtypy, w których kompilator może sprawdzić, czy każda typecaseinstrukcja obejmuje wszystkie podtypy.

Patchowanie małp i programowanie zorientowane na aspekt

Systemy typu dynamicznego znacznie ułatwiają różnorodne techniki prototypowania. W językach, w których typy są reprezentowane przez mapy skrótów od ciągów znaków do funkcji (np. Python, JavaScript, Ruby), dość łatwo jest globalnie zmienić zachowanie każdego modułu zależnego od określonego typu, po prostu dynamicznie modyfikując mapę skrótu reprezentującą to rodzaj.

Chociaż istnieją oczywiste sposoby, w jakie łatanie małp może być utrudnione w utrzymywaniu programów, istnieją również sposoby, w których można go używać raczej dla „dobra” niż „zła”. W szczególności w przypadku programowania zorientowanego na aspekty można zastosować techniki łatania małp, takie jak modyfikacja typu pliku, aby wskazywać na zwirtualizowany system plików, pozwalający na budowę infrastruktury testowania jednostek w celu „darmowego” lub modyfikowanie prostych typów wyjątków, aby drukuj komunikaty dziennika za każdym razem, gdy zostaną złapane w celu lepszej debuggowania.

W przeciwieństwie do generycznego i polimorfizmu podtypów, w których w latach 70. dostępne były kluczowe pomysły na sprawdzanie statyczne, sprawdzanie statyczne programowania aspektowego jest (myślę) aktywnym obszarem badań. Nie wiem za dużo o tym, że istnieje język o nazwie AspectJ od około 2001 roku.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.