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 case
lub switch
oś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 typecase
instrukcja 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.