Jakie są zalety i ograniczenia języków typu dynamicznego w porównaniu do języków typu statycznego?
Zobacz także : co z zamiłowaniem do dynamicznych języków (o wiele bardziej argumentacyjny wątek ...)
Jakie są zalety i ograniczenia języków typu dynamicznego w porównaniu do języków typu statycznego?
Zobacz także : co z zamiłowaniem do dynamicznych języków (o wiele bardziej argumentacyjny wątek ...)
Odpowiedzi:
Zdolność interpretera do wnioskowania o konwersjach typów i czcionek przyspiesza czas programowania, ale może także wywoływać awarie środowiska wykonawczego, których po prostu nie można uzyskać w języku o typie statycznym, w którym można je złapać w czasie kompilacji. Ale który z nich jest lepszy (a nawet jeśli to zawsze prawda) jest obecnie gorąco dyskutowany w społeczności (i od dłuższego czasu).
Dobre podejście do tej kwestii pochodzi z pisania statycznego tam, gdzie jest to możliwe, pisania dynamicznego w razie potrzeby: koniec zimnej wojny między językami programowania autorstwa Erika Meijera i Petera Draytona z firmy Microsoft:
źródło
Systemy typu statycznego starają się eliminować niektóre błędy statycznie, sprawdzając program bez uruchamiania go i próbując udowodnić solidność pod pewnymi względami. Niektóre systemy typów są w stanie wychwycić więcej błędów niż inne. Na przykład język C # może wyeliminować wyjątki zerowego wskaźnika, jeśli jest używany poprawnie, podczas gdy Java nie ma takiej mocy. Twelf ma system typów, który faktycznie gwarantuje zakończenie prób , „rozwiązując” problem zatrzymania .
Jednak żaden system typów nie jest idealny. Aby wyeliminować określoną klasę błędów, muszą także odrzucić niektóre doskonale poprawne programy, które naruszają reguły. Właśnie dlatego Twelf tak naprawdę nie rozwiązuje problemu zatrzymania, po prostu unika go, rzucając dużą liczbę doskonale ważnych dowodów, które kończą się w dziwny sposób. Podobnie system typów Java odrzuca
PersistentVector
implementację Clojure z powodu użycia heterogenicznych tablic. Działa w czasie wykonywania, ale system typów nie może go zweryfikować.Z tego powodu większość systemów typu zapewnia „ucieczki”, sposoby na zastąpienie sprawdzania statycznego. W większości języków mają one postać rzutowania, chociaż niektóre (jak C # i Haskell) mają całe tryby, które są oznaczone jako „niebezpieczne”.
Subiektywnie lubię pisanie statyczne. Prawidłowo zaimplementowany (podpowiedź: nie Java), system typu statycznego może być ogromną pomocą w usuwaniu błędów przed awarią systemu produkcyjnego. Języki o typie dynamicznym zwykle wymagają więcej testów jednostkowych, co w najlepszym przypadku jest nużące. Ponadto języki o typie statycznym mogą mieć pewne funkcje, które są niemożliwe lub niebezpieczne w systemach typu dynamicznego ( przychodzą mi na myśl niejawne konwersje ). Wszystko zależy od wymagań i subiektywnego gustu. Nie zbudowałbym kolejnego Eclipse w Rubim, niż próbowałbym napisać skrypt tworzenia kopii zapasowej w asemblerze lub załatać jądro za pomocą Java.
Aha, a ludzie, którzy mówią, że „ pisanie x jest 10 razy wydajniejsze niż pisanie y ”, po prostu dmuchają dymem. Pisanie dynamiczne może „czuć się” szybciej w wielu przypadkach, ale traci sens, gdy faktycznie próbujesz uruchomić fantazyjną aplikację . Podobnie, statyczne pisanie może wydawać się być idealną siatką bezpieczeństwa, ale jedno spojrzenie na niektóre bardziej skomplikowane ogólne definicje typów w Javie powoduje, że większość programistów pędzi w stronę osób niewidomych. Nawet przy systemach typu i wydajności nie ma srebrnej kuli.
Uwaga końcowa: nie martw się o wydajność podczas porównywania pisania statycznego z dynamicznym pisaniem. Nowoczesne JIT, takie jak V8 i TraceMonkey, niebezpiecznie zbliżają się do wydajności w języku statycznym. Fakt, że Java faktycznie kompiluje się do z natury dynamicznego języka pośredniego, powinien być wskazówką, że w większości przypadków dynamiczne pisanie nie jest ogromnym zabójcą wydajności, jak niektórzy to robią.
źródło
dadd
ponieważ z góry wie, że operandy sądouble
s.Cóż, obie są bardzo, bardzo, bardzo niezrozumiane, a także dwie zupełnie różne rzeczy. które nie wykluczają się wzajemnie .
Typy statyczne są ograniczeniem gramatyki języka. Można by powiedzieć, że statycznie wpisane języki nie są pozbawione kontekstu. Prosta prawda jest taka, że niewygodne jest wyrażanie języka w sposób rozsądny w gramatyce bezkontekstowej, która nie traktuje wszystkich swoich danych po prostu jako wektorów bitowych. Systemy typu statycznego są częścią gramatyki języka, jeśli w ogóle istnieją, po prostu ograniczają go bardziej niż gramatyka bezkontekstowa, tak więc sprawdzanie gramatyki odbywa się w dwóch etapach nad źródłem. Typy statyczne odpowiadają matematycznemu pojęciu teorii typów, teoria typów w matematyce po prostu ogranicza legalność niektórych wyrażeń. Nie mogę powiedzieć
3 + [4,7]
matematyki, że wynika to z teorii typów.Typy statyczne nie są zatem sposobem „zapobiegania błędom” z teoretycznego punktu widzenia, są ograniczeniem gramatyki. Rzeczywiście, pod warunkiem, że +, 3 i interwały mają zwykle ustawione teoretyczne definicje, jeśli usuniemy system typów
3 + [4,7]
ma całkiem dobrze określony wynik, który jest zbiorem. „błędy typu środowiska wykonawczego” teoretycznie nie istnieją, praktycznym zastosowaniem systemu typów jest zapobieganie operacjom, które dla ludzi nie miałyby sensu. Oczywiście operacje wciąż polegają jedynie na przesuwaniu i manipulowaniu bitami.Problem polega na tym, że system typów nie może zdecydować, czy takie operacje będą miały miejsce, czy nie, czy będzie to dozwolone. Podobnie jak w, dokładnie podziel zestaw wszystkich możliwych programów na te, które będą miały „błąd typu”, a te, które nie są. Może zrobić tylko dwie rzeczy:
1: udowodnij, że błędy programu wystąpią w programie
2: udowodnij, że nie wystąpią w programie
Może się to wydawać, że sam sobie zaprzeczam. Ale to, co robi moduł sprawdzający typu C lub Java, to odrzuca program jako „niegramatyczny” lub jak nazywa go „błędem typu”, jeśli nie może się powieść o 2. Nie może udowodnić, że się nie wydarzy, to nie znaczy, że się nie zdarzy, to po prostu oznacza, że nie może tego udowodnić. Może się zdarzyć, że program, który nie będzie zawierał błędu typu, zostanie odrzucony tylko dlatego, że nie może tego udowodnić kompilator. Prostym przykładem jest
if(1) a = 3; else a = "string";
, z pewnością ponieważ zawsze jest to prawdą, gałąź else nigdy nie zostanie wykonana w programie i nie wystąpi błąd typu. Ale nie może udowodnić tych przypadków w sposób ogólny, więc zostało odrzucone. Jest to główna słabość wielu statycznie typowanych języków, ponieważ chroniąc cię przed sobą, koniecznie jesteś chroniony również w przypadkach, gdy nie potrzebujesz.Ale, w przeciwieństwie do powszechnego przekonania, istnieją również statyczne języki, które działają zgodnie z zasadą 1. Po prostu odrzucają wszystkie programy, których mogą udowodnić, że spowoduje błąd typu i przekazują wszystkie programy, których nie potrafią. Możliwe więc, że pozwalają programom, w których występują błędy typu, dobrym przykładem jest Typed Racket, hybryda pomiędzy pisaniem dynamicznym i statycznym. I niektórzy twierdzą, że masz w tym systemie to, co najlepsze z obu światów.
Kolejną zaletą typowania statycznego jest to, że typy są znane w czasie kompilacji, a zatem kompilator może z nich korzystać. Jeśli robimy to w Javie,
"string" + "string"
lub3 + 3
oba+
tokeny w tekście na końcu reprezentują zupełnie inną operację i układ odniesienia, kompilator wie, który wybrać spośród samych typów.Teraz zamierzam przedstawić bardzo kontrowersyjne stwierdzenie, ale pamiętajcie: „dynamiczne pisanie” nie istnieje .
Brzmi bardzo kontrowersyjnie, ale to prawda, dynamicznie pisane języki są z teoretycznego punktu widzenia nietypowe . Są to tylko statycznie pisane języki z tylko jednym typem. Innymi słowy, są to języki, które w praktyce są generowane gramatycznie przez gramatykę bezkontekstową.
Dlaczego nie mają typów? Ponieważ każda operacja jest zdefiniowana i dozwolona dla każdego operanta, czym dokładnie jest „błąd typu środowiska wykonawczego”? To z teoretycznego przykładu wyłącznie efekt uboczny . Jeśli robienie,
print("string")
które wypisuje łańcuch, jest operacją, to i taklength(3)
pierwsza z nich ma efekt uboczny zapisustring
na standardowe wyjście, druga po prostuerror: function 'length' expects array as argument.
to jest to. Z teoretycznego punktu widzenia nie ma czegoś takiego jak dynamicznie pisany język. Są bez typuW porządku, oczywistą zaletą „dynamicznie typowanego” języka jest moc ekspresji, a system typów jest niczym innym jak ograniczeniem mocy ekspresji. Ogólnie rzecz biorąc, języki z systemem typów rzeczywiście miałyby określony wynik dla wszystkich tych operacji, które nie są dozwolone, jeśli system typów byłby po prostu zignorowany, wyniki po prostu nie miałyby sensu dla ludzi. Wiele języków traci kompletność Turinga po zastosowaniu systemu typów.
Oczywistą wadą jest to, że mogą wystąpić operacje, które przyniosłyby bezsensowne dla ludzi wyniki. Aby temu zapobiec, dynamicznie pisane języki zwykle redefiniują te operacje, zamiast generować ten nonsensowny wynik, na nowo definiują go jako efekt uboczny polegający na zapisaniu błędu i prawdopodobnie całkowitym zatrzymaniu programu. W ogóle nie jest to „błąd”, w rzeczywistości specyfikacja języka implikuje to, jest to tak samo zachowanie języka, jak drukowanie łańcucha z teoretycznej perspektywy. Systemy typów zmuszają zatem programistę do uzasadnienia przepływu kodu, aby upewnić się, że tak się nie stanie. A zresztą rozum, że takmoże się przydać w niektórych punktach do debugowania, pokazując, że wcale nie jest to „błąd”, ale dobrze zdefiniowana właściwość języka. W efekcie jedyna pozostałość „dynamicznego pisania”, którą ma większość języków, chroni przed dzieleniem przez zero. Właśnie tym jest dynamiczne pisanie, nie ma typów, nie ma więcej typów niż to, że zero jest innym typem niż wszystkie inne liczby. To, co ludzie nazywają „typem”, jest po prostu inną właściwością układu odniesienia, taką jak długość tablicy lub pierwszy znak ciągu. Wiele dynamicznie wpisywanych języków pozwala także pisać takie rzeczy
"error: the first character of this string should be a 'z'"
.Inną rzeczą jest to, że dynamicznie pisane języki mają typ dostępny w czasie wykonywania i zwykle mogą go sprawdzić, poradzić sobie z nim i zdecydować na jego podstawie. Oczywiście w teorii nie różni się to od uzyskania pierwszego znaku tablicy i zobaczenia, co to jest. W rzeczywistości możesz stworzyć swój własny dynamiczny C, po prostu użyj tylko jednego typu, takiego jak long long int i użyj pierwszych 8 bitów, aby zapisać swój „typ” i odpowiednio pisać funkcje, które sprawdzają go i wykonują dodawanie zmiennoprzecinkowe lub całkowite. Masz statycznie wpisany język z jednym typem lub język dynamiczny.
W praktyce pokazuje to, że języki o typie statycznym są zwykle używane w kontekście pisania oprogramowania komercyjnego, podczas gdy języki o typie dynamicznym są zwykle używane w kontekście rozwiązywania niektórych problemów i automatyzacji niektórych zadań. Pisanie kodu w statycznie pisanych językach po prostu zajmuje dużo czasu i jest uciążliwe, ponieważ nie możesz robić rzeczy, o których wiesz, że okażą się w porządku, ale system typów wciąż chroni cię przed sobą przed błędami, których nie popełniasz. Wielu programistów nawet nie zdaje sobie sprawy, że to robią, ponieważ jest to w ich systemie, ale kiedy piszesz w językach statycznych, często omijasz fakt, że system typów nie pozwala ci robić rzeczy, które nie mogą pójść źle, ponieważ to nie mogę udowodnić, że nie pójdzie źle.
Jak zauważyłem, „typowanie statyczne” ogólnie oznacza przypadek 2, winny, dopóki nie zostanie udowodniony niewinności. Ale niektóre języki, które nie wywodzą swojego systemu typów z teorii typów, w ogóle stosują zasadę 1: Niewinni aż do udowodnienia winy, co może być idealną hybrydą. Więc może Typed Racket jest dla Ciebie.
Ponadto, dla bardziej absurdalnego i ekstremalnego przykładu, obecnie wdrażam język, w którym „typy” są naprawdę pierwszym znakiem tablicy, są to dane, dane „typu”, „typ”, który jest sam w sobie typ i układ odniesienia, jedyny układ odniesienia, który ma się jako typ. Typy nie są skończone ani ograniczone statycznie, ale nowe typy mogą być generowane na podstawie informacji o środowisku wykonawczym.
źródło
Być może największą zaletą dynamicznego pisania jest płytsza krzywa uczenia się. Nie ma żadnego systemu typów do nauczenia się i nie jest trywialna składnia dla przypadków narożnych, takich jak ograniczenia typu. To sprawia, że pisanie dynamiczne jest dostępne dla znacznie większej liczby osób i jest wykonalne dla wielu osób, dla których zaawansowane systemy typu statycznego są poza zasięgiem. W związku z tym dynamiczne pisanie przyjęło się w kontekście edukacji (np. Scheme / Python na MIT) i języków specyficznych dla domeny dla osób niebędących programistami (np. Mathematica ). Języki dynamiczne przyjęły się także w niszach, w których mają niewielką lub żadną konkurencję (np. Javascript).
Najbardziej zwięzłe, dynamicznie typowane języki (np. Perl, APL, J, K, Mathematica ) są specyficzne dla dziedziny i mogą być znacznie bardziej zwięzłe niż najbardziej zwięzłe języki ogólnego przeznaczenia o typie statycznym (np. OCaml ) w niszach, dla których zostały zaprojektowane .
Główne wady dynamicznego pisania to:
Błędy typu wykonawczego.
Osiągnięcie tego samego poziomu poprawności może być bardzo trudne lub wręcz praktycznie niemożliwe i wymaga znacznie więcej testów.
Brak dokumentacji zweryfikowanej przez kompilator.
Niska wydajność (zwykle w czasie wykonywania, ale czasem w czasie kompilacji, np. Schemat Stalina) i nieprzewidywalna wydajność z powodu zależności od wyrafinowanych optymalizacji.
Osobiście wychowałem się na dynamicznych językach, ale nie chciałbym ich dotykać 40-biegunowym słupkiem jako profesjonalista, chyba że nie byłoby innych realnych opcji.
źródło
Z artykułu Artima : Typing: Strong vs. Słaby, Statyczny vs. Dynamiczny artykuł:
W pracy Pascala Costanzy „ Dynamiczne vs. statyczne pisanie - analiza oparta na wzorach” (PDF) twierdzi, że w niektórych przypadkach pisanie statyczne jest bardziej podatne na błędy niż pisanie dynamiczne. Niektóre języki o typie statycznym wymuszają ręczną emulację pisania dynamicznego w celu wykonania „Właściwej rzeczy”. Omówiono to w Lambda the Ultimate .
źródło
To zależy od kontekstu. Istnieje wiele korzyści, które są odpowiednie zarówno dla systemu dynamicznego pisania, jak i silnego pisania. Uważam, że przepływ języka typów dynamicznych jest szybszy. Języki dynamiczne nie są ograniczone atrybutami klas i myśleniem kompilatora o tym, co dzieje się w kodzie. Masz trochę swobody. Co więcej, język dynamiczny zwykle jest bardziej wyrazisty i powoduje mniej dobrego kodu. Mimo to jest bardziej podatny na błędy, co również jest wątpliwe i zależy bardziej od pokrycia testem jednostkowym. Jest to łatwy prototyp z dynamicznym językiem, ale konserwacja może stać się koszmarem.
Główną przewagą nad systemem typowania statycznego jest obsługa IDE i na pewno statyczny analizator kodu. Po każdej zmianie kodu stajesz się bardziej pewny kodu. Utrzymanie to spokój dzięki takim narzędziom.
źródło
Istnieje wiele różnych rzeczy na temat języków statycznych i dynamicznych. Dla mnie główna różnica polega na tym, że w językach dynamicznych zmienne nie mają ustalonych typów; zamiast tego typy są powiązane z wartościami. Z tego powodu dokładny kod, który zostanie wykonany, nie jest określony do czasu uruchomienia.
We wczesnych lub naiwnych implementacjach jest to ogromny problem z wydajnością, ale współczesne JIT są kusząco zbliżone do tego, co można uzyskać dzięki optymalizacji kompilatorów statycznych. (w niektórych skrajnych przypadkach, nawet lepiej niż to).
źródło
Chodzi o właściwe narzędzie do pracy. Żadne z nich nie jest lepsze w 100% przypadków. Oba systemy zostały stworzone przez człowieka i mają wady. Przykro nam, ale jesteśmy do kitu i robimy idealne rzeczy.
Lubię dynamiczne pisanie, ponieważ zrywa mi się z drogi, ale tak, błędy w czasie wykonywania mogą pełzać, których nie planowałem. Gdzie jako wpisywanie statyczne może naprawić wyżej wymienione błędy, ale doprowadza początkującego (w językach pisanych na maszynie) programistę do szaleństwa, próbując rzucić między stałym char i ciągiem.
źródło
Pisanie statyczne: Języki, takie jak Java i Scala, są pisane statycznie.
Zmienne muszą zostać zdefiniowane i zainicjowane, zanim zostaną użyte w kodzie.
na przykład int x; x = 10;
System.out.println (x);
Pisanie dynamiczne: Perl jest językiem pisanym dynamicznie.
Zmienne nie muszą być inicjowane, zanim zostaną użyte w kodzie.
y = 10; użyj tej zmiennej w dalszej części kodu
źródło