Czy wpisywanie statyczne jest warte kompromisów?


108

Zacząłem pisać w Pythonie przede wszystkim tam, gdzie nie ma bezpieczeństwa typu, potem przeniosłem się do C # i Java, gdzie jest. Przekonałem się, że mogę pracować trochę szybciej i mniej problemów z Pythonem, ale z drugiej strony moje aplikacje C # i Java są na znacznie wyższym poziomie złożoności, więc chyba nigdy nie poddałem Pythonowi prawdziwego testu warunków skrajnych.

Obozy w Javie i C # sprawiają, że brzmi to tak, jakby bez tego rodzaju bezpieczeństwa, większość ludzi wpadłaby na wszelkiego rodzaju straszne błędy po lewej stronie i byłoby więcej kłopotów niż jest warta.

To nie jest porównanie językowe, więc nie rozwiązuj problemów takich jak kompilacja czy interpretacja. Czy bezpieczeństwo typu jest warte uderzenia w szybkość rozwoju i elastyczność? DLACZEGO?

osobom, które chciały uzyskać przykład, że dynamiczne pisanie jest szybsze:

„Podczas programowania używaj dynamicznie pisanego języka. Daje to szybsze informacje zwrotne, czas zawracania i szybkość programowania”. - http://blog.jayway.com/2010/04/14/static-typing-is-the-root-of-all-evil/


15
To pytanie jest przeciwieństwem jakich argumentów przemawia za słabym pisaniem na klawiaturze? .
Nicole

8
@Prof Plum: czy mogę zażądać dowodu na szybkość rozwoju i elastyczność? Ponieważ mówimy o konkretnym aspekcie bezpieczeństwa typu , przy użyciu Javalub C#byłby on niejednoznaczny, ich sposób zapewnienia go NIE jest jedynym ...
Matthieu M.,

32
Dzięki staranności w ścisłym języku możesz zminimalizować „bóle głowy”, a nawet możesz zauważyć wzrost prędkości z powodu automatycznego uzupełniania IDE, generowania kodu i podpowiedzi do kodu.
Nicole

9
@Prof Plum: Rozumiem, nie oczekuję, że ty (lub ktokolwiek naprawdę) w pełni przetestowałeś każdy język, jaki kiedykolwiek stworzono ^^ Problem polega na tym, że większość osób, które widziałem, narzeka na niektóre specyficzne aspekty języków programowania (statyczne Wpisywanie często przychodzi) na ogół narzekają na określoną implementację i nie zdają sobie z tego sprawy.
Matthieu M.

5
@Prof Plum, wszystko, co ten post na blogu naprawdę mówi o szybkości, to łysy stwierdzenie: „Każdy, kto poważnie pracował z nowoczesnym dynamicznie pisanym językiem, takim jak Ruby lub Smalltalk, wie, że jest bardziej produktywny”. Brak rzeczywistych przykładów tego, jak w praktyce przyspiesza rozwój.
Carson63000,

Odpowiedzi:


162

To mit, że programiści nie muszą się martwić o typy w dynamicznie pisanych językach.

W dynamicznie wpisywanych językach:

  • Nadal musisz wiedzieć, czy pracujesz z tablicą, liczbą całkowitą, łańcuchem, tablicą skrótu, odwołaniem do funkcji, słownikiem, obiektem lub czymkolwiek innym.

  • Jeśli jest to obiekt, musisz wiedzieć, do której klasy należy.

  • Przypisanie jednego z tych typów do zmiennej lub parametru funkcji, który ma być innym typem, prawie zawsze jest błędem.

  • Na niższym poziomie rzeczy, takie jak liczba bitów lub liczba często podpisywana i niepodpisana, wciąż muszą zostać uwzględnione, na przykład w przypadku zapełniania pakietu TCP.

  • Możesz napotkać problemy, w których dostajesz zero, w którym naprawdę chcesz pusty ciąg. Innymi słowy, nadal debugujesz błędy niedopasowania typu. Jedyną prawdziwą różnicą jest to, że kompilator nie wychwytuje błędów.

  • Twierdzę, że nawet nie oszczędzasz dużo pisania - ponieważ zwykle chcesz dokumentować w komentarzach, jakiego typu są parametry funkcji zamiast dokumentować je w kodzie. Dlatego bloki komentarzy w stylu doxygen są znacznie bardziej popularne w praktyce w kodzie dynamicznie wpisywanym, gdzie w językach o typie statycznym najczęściej widzisz je tylko dla bibliotek.

Nie oznacza to, że programowanie w językach dynamicznie wpisywanych nie jest przyjemniejsze, ponieważ kompilator nie zawsze jest na twoich plecach, a doświadczeni programiści nie mają trudności ze znalezieniem i naprawieniem błędów, które i tak wychwytują pisanie statyczne , ale jest to zupełnie odrębny problem od rzekomego wzrostu wydajności lub zmniejszenia liczby błędów, w przypadku których dynamiczne pisanie jest w najlepszym wypadku nawet przy pisaniu statycznym.


10
Musiałbym trochę zakwestionować to, że doświadczeni programiści nie robią / nie wprowadzają tego rodzaju błędów. Dobrzy programiści, którzy są pokorni i zdają sobie sprawę z możliwości popełniania błędów (a doświadczeni programiści nie zawsze tacy są), są mniej skłonni do tworzenia tych błędów.
Jay Jay Jay

12
Nie mogę zgodzić się więcej z „Argumentowałbym, że nie oszczędzasz nawet dużo pisania”. Ostatecznie dokumentujesz typy w komentarzach i sprawdzasz je w swoich testach, co w ogóle wymaga więcej pisania i konserwacji (w końcu musisz pamiętać, aby aktualizować te komentarze za każdym razem, gdy zmieniają się twoje typy, a częściej nie będziesz tego robić) ).
Severyn Kozak

W naszym sklepie Python spędzamy znacznie więcej czasu na dokumentowaniu typów, niż oszczędzamy na pełnym statycznym języku, takim jak C # lub Java. Warto również zauważyć, że nowsza generacja języków, takich jak Go i Rust, korzysta z wnioskowania o typie, więc wpisujesz „x: = new (Object)” zamiast „Object x = new Object ()”.
weberc2

Zgadzam się z tobą, gdy mówisz, że dynamiczny język jest przyjemniejszy, ale nie wiem dlaczego. Czy masz na to wyjaśnienie?
Rodrigo Ruiz,

Tak, zamiast podawać typ zmiennych, można użyć domyślnych wartości lub testów jednostkowych (wbudowanych dokumentów) w Pythonie. Również w Pythonie czasami możesz mieć dziwne błędy z błędami w pisowni [mniej prawdopodobne, że użyjesz autouzupełniania, którego często można używać, chociaż nie zawsze w dynamicznych językach] i musisz dowiedzieć się, czy self.bread = 5 wprowadza chleb lub redefiniowanie go.
aoeu256

123

Gdy typy stają się silniejsze, mogą ci pomóc bardziej - jeśli użyjesz ich poprawnie zamiast z nimi walczyć. Zaprojektuj swoje typy tak, aby odzwierciedlały przestrzeń problemu, a błędy logiczne będą bardziej prawdopodobne, że staną się niedopasowane w czasie kompilacji zamiast awarii środowiska uruchomieniowego lub nonsensownych wyników.


37
+1! „błędy logiczne częściej stają się niezgodnościami typu kompilacji zamiast awarii środowiska wykonawczego lub bzdurnych wyników”: Naprawdę dobra odpowiedź! Kiedy poświęcam więcej czasu na projektowanie moich typów, kod podąża bardziej naturalnie i często jest poprawny zaraz po skompilowaniu. Projektowanie typu oznacza zrozumienie domeny i jej operacji.
Giorgio

78

Uwaga: Jestem miłośnikiem typów;)

Trudno odpowiedzieć na twoje pytanie: jakie są te kompromisy ?

Podam przykład skrajny: Haskell , jest on wpisany statycznie. Być może jest to jeden z najmocniejszych typów języków.

Jednak Haskell obsługuje programowanie ogólne , w tym sensie, że piszesz metody, które działają z dowolnym typem zgodnym z określoną koncepcją (lub interfejsem).

Ponadto Haskell używa wnioskowania typu , dzięki czemu nigdy nie musisz deklarować typu swoich zmiennych. Są one obliczane statycznie podczas kompilacji, podobnie jak interpreter Pythona obliczałby je z uruchomionym programem.

Przekonałem się, że większość ludzi, którzy mają problemy z pisaniem na klawiaturze, faktycznie narzekają na coś innego (gadatliwość, ból zamiany jednego rodzaju na inny), ale Haskell nie wykazuje żadnego z tych problemów, podczas gdy jest wpisywany statycznie ...


Przykład zwięzłości:

-- type
factorial :: Integer -> Integer

-- using recursion
factorial 0 = 1
factorial n = n * factorial (n - 1)

Oprócz wbudowanego wsparcia, trudno jest uzyskać krótką prezentację.

Przykład programowania ogólnego:

> reverse "hell­o" -- Strings are list of Char in Haskell
=> "olleh"
> reverse [1, 2, 3, 4, 5]
=> [5,4,3,2,1]

Przykład wnioskowania typu:

> :t rever­se "hell­o"
:: [Char]

które można obliczyć po prostu:

  • "hello"to lista Char(wyrażona jako [Char])
  • reversezastosowane do typu [A]zwraca typ[A]

Wypróbuj w swojej przeglądarce


4
Aby zagrać w adwokata diabła, jednym z kompromisów na rzecz języków dynamicznych (przynajmniej podczas prototypowania) jest to, że o ile deklaracje typu mogą służyć temu samemu celowi, co niektóre testy jednostkowe, mogą także utrwalać interfejsy w taki sam sposób, jak robią to testy jednostkowe ( choć z pewnością przy mniejszym obciążeniu). Również języki wpisywane statycznie bez przymusu, choć bezpieczniejsze, wymagają jawnego rzutowania tekstu (szczególnie gdy typ nie jest wystarczająco ogólny), co może odwracać uwagę od zwięzłości.
TR

7
Nie znam Haskella, ale +1 za „faktycznie narzekali na coś innego (gadatliwość, ból z zamiany jednego rodzaju na inny)”
Nicole

1
@Aidan: Haskell to ewoluujący język. Haskell 98 był ulepszeniem w stosunku do Haskell 1.4; Haskell 2010 był lepszy od tego. Tymczasem warto zauważyć, że racją bytu Haskella była pomoc w badaniu systemów typów; Klasy typów wieloparametrowych są jednym z przykładów, w których udało się wyjaśnić przydatne rozszerzenie systemu typów. (Z drugiej strony, zależności funkcjonalne wyglądają na ślepy zaułek.)
geekozaur

4
@Matthieu: WRT „Być może jednym z najsilniej wpisany języków, które istnieją w rzeczywistości”, zobaczę swoją Haskell i podnieść cię Agda i Coq . (Przyznaję, że jest to najprawdopodobniej najsilniejszy praktycznie praktyczny język.)
geekosaur

1
@Matthieu: Asystenci Proof są bezpośrednią aplikacją korespondencji Curry-Howard, więc są w sercu języków programowania (choć z raczej ograniczonymi standardowymi bibliotekami). Są na czele badań typu zależnego, ponieważ potrzebujesz typów zależnych, aby dobrze wykorzystać korespondencję „typy są propozycjami”.
geekozaur

37

Lubię zarówno języki statyczne, jak i dynamiczne. Dwie największe zalety bezpieczeństwa typu to dla mnie:

1) Często można właściwie wywnioskować, co funkcja robi wyłącznie na podstawie podpisu typu (jest to szczególnie prawdziwe w językach funkcjonalnych, takich jak Haskell).

2) Gdy wykonasz znaczący refaktor, kompilator automatycznie powie ci wszystko, co musisz zrobić, aby wszystko działało. Kiedy refaktoryzuję coś w C ++, moja procedura często po prostu a) zmienia jedną część, którą wiem, że chcę zmienić, a następnie b) naprawia każdy błąd kompilacji.


Dokładnie tak samo ze mną i za każdym razem, gdy chcę coś refaktoryzować (najczęściej używam golang / maszynopis / java), tak, te 2 kroki są tymi, których każdy potrzebuje. zmień jedną część, a następnie napraw wszystkie błędy kompilacji :) idealna odpowiedź.
Nishchal Gautam

29

Osobiście uważam, że bezpieczeństwo typu pomaga mi szybciej się rozwijać w mojej obecnej pracy. Kompilator wykonuje dla mnie sprawdzanie poczytalności prawie podczas pisania, co pozwala mi skupić się na logice biznesowej, którą wdrażam.

Najważniejsze dla mnie jest to, że chociaż tracę trochę elastyczności, zyskuję trochę czasu, który w przeciwnym razie spędziłby na śledzeniu problemów z typem.


13

Wokół debaty jest wiele silnych opinii, ale oczywiście to nie jest kwestia opinii, to fakty . Powinniśmy więc spojrzeć na badania empiryczne . Dowody z tego są jasne:

Tak , pisanie statyczne jest warte kompromisów - i to nie tylko odrobinę, ale w rzeczywistości znacznie . W rzeczywistości solidne dowody wskazują, że wpisywanie statyczne może zmniejszyć liczbę błędów w kodzie o co najmniej 15% (i jest to niski szacunek, faktyczny odsetek jest prawie na pewno większy). Jest to szokująco wysoka liczba: myślę, że nawet większość zwolenników pisania statycznego nie pomyślałaby, że ma to tak drastyczną różnicę.

Zastanów się: jeśli ktoś powiedział ci, że istnieje prosty sposób na zmniejszenie błędów w twoim projekcie o 15% w ciągu jednej nocy, nie powinno to być żadnym problemem. 1 To prawie przysłowiowa srebrna kula.

Dowody zostały przedstawione w artykule Zheng Gao, Christian Bird i Earl T. Barr w artykule Aby wpisać lub nie wpisać: Określenie wykrywalnych błędów w JavaScript . Zachęcam wszystkich do lektury, jest to dobrze napisany artykuł, który przedstawia przykładowe badania.

Trudno jest zwięźle streścić, jak rygorystycznie autorzy przeprowadzili analizę, ale oto (bardzo przybliżony) zarys:

TypeScript i Flow to dwa języki programowania oparte na JavaScript, które pozostając kompatybilne, dodają podpowiedzi i statyczne sprawdzanie typów. Pozwala to na powiększenie istniejącego kodu o typy, a następnie na sprawdzenie typu.

Badacze zebrali projekty Open Source napisane w języku JavaScript z GitHub, przejrzeli zgłoszone błędy i próbowali zredukować każdy z zgłoszonych błędów do fragmentu kodu, który zostałby przechwycony przez statyczny moduł sprawdzania typu TypeScript lub Flow. To pozwoliło im oszacować dolną granicę odsetka błędów, które można naprawić za pomocą pisania statycznego.

Badacze podjęli surowe środki ostrożności, aby ich analiza nie uwzględniła błędu niezwiązanego z typem jako powiązanego z typami. 2)

W porównaniu do poprzednich badań to nowe badanie ma szczególne zalety:

  • Istnieje bezpośrednie porównanie pisania statycznego i dynamicznego, z kilkoma (jeśli w ogóle) mylącymi czynnikami, ponieważ jedyną różnicą między JavaScript a TypeScript / Flow jest pisanie.
  • Wykonują replikację w wielu wymiarach, sprawdzając zarówno TypeScript, jak i Flow (tj. Różne systemy typów), a także pozwalając różnym osobom odtwarzać (ręczną) adnotację typu w celu naprawienia błędów. I wykonują to w wielu bazach kodu z różnych projektów.
  • Artykuł mierzy bezpośredni wpływ pisania statycznego na możliwe do naprawienia błędy (zamiast pewnej bardziej niejasnej jakości).
  • Autorzy określają rygorystyczny model tego, co mierzyć i jak z góry. Co więcej, ich opis jest niezwykle jasny i ułatwia analizę pod kątem wad (zawsze dobrze jest, gdy dokument badawczy otwiera się na ataki: jeśli żaden atak nie zdoła podważyć argumentów, wyjdzie jeszcze silniejszy). 3)
  • Przeprowadzają odpowiednią analizę mocy , aby ich wielkość próbki była wystarczająca, a ich późniejsza analiza statystyczna jest hermetyczna.
  • Są zbyt konserwatywni, aby wykluczyć mylące wyjaśnienia i mierzą tylko jedną ruchomą część. Ponadto ograniczają swoją analizę do błędów, które można natychmiast naprawić, włączając typy i wykluczają wszystko, co może wymagać bardziej zaawansowanego refaktoryzacji w celu dostosowania do pisania. Tak więc w rzeczywistości efekt jest znacznie większy, ale na pewno nie mniejszy niż to, co zgłosili.
  • I w końcu nie widzą żadnego efektu, ale oszałamiającą różnicę. Pomimo zbyt zachowawczej procedury, nawet na dolnym końcu 95% przedziału ufności stwierdzają, że istnieje co najmniej 10% błędów, które zniknęłyby po minimalnym dodaniu kontroli typu.

O ile w papierze nie ma fundamentalnej wady, której nikt jeszcze nie odkrył, papier bez wątpienia wykazuje dużą zaletę pisania statycznego, prawie za darmo. 4


Historycznie rzecz biorąc, badania nad dyscyplinami pisania na klawiaturze miały gwałtowny początek, ponieważ przez długi czas dowody wcale nie były jasne. Powodem tego jest to, że robi systematyczne eksperymenty w celu zbadania wpływu statyczne vs dynamiczne typowanie nie jest łatwe: systematyczna eksperyment musi izolować efekt Badamy. I niestety nie możemy wyodrębnić efektu dyscypliny pisania, ponieważ jest on związany z językami programowania.

W rzeczywistości istniały języki programowania, które umożliwiały zarówno pisanie statyczne, jak i dynamiczne w różnych dialektach (np. VB z Option Strict Onlub Offlub statycznie wpisany Lisp). Nie nadawały się one jednak do bezpośredniego porównania, co najważniejsze, ponieważ nie istniały wystarczająco duże bazy kodu, które pozwalałyby na bezpośrednie porównanie. W najlepszym wypadku moglibyśmy je porównać w „warunkach laboratoryjnych”, w których badani losowo rozwiązują zadanie w statycznie lub dynamicznie typowanym wariancie języka.

Niestety te sztuczne zadania programistyczne nie modelują dobrze użycia w świecie rzeczywistym. W szczególności wiele z nich ma niewielki zakres i rozwiązuje dobrze zdefiniowany problem, który można streścić na połowie strony tekstu.

Na szczęście dzieje się tak w przeszłości, ponieważ TypeScript, Flow i JavaScript są w rzeczywistości tymi samymi językami, z wyjątkiem pisania statycznego, oraz ponieważ istnieje obszerny zestaw danych kodu i błędów, z których można pobierać próbki.


1 Zainspirowany cytatem z oryginału.

2 Nie do końca jestem z tego zadowolony: jedną z głównych zalet statycznie typowanych języków jest to, że pozornie niezwiązane z typem problemy można sformułować w sposób, który można sprawdzić statycznie. Przekształca to wiele błędów logicznych w błędy typu, co drastycznie zwiększa liczbę błędów, które można wykryć podczas pisania statycznego. W rzeczywistości papier z grubsza klasyfikuje błędy niezwiązane z typem i twierdzę, że duży procent z nich można w rzeczywistości złapać przez pisanie statyczne.

3 Zapraszam każdego, a zwłaszcza zwolenników pisania dynamicznego, aby starał się znaleźć nieadresowane błędy w analizie. Nie sądzę, że jest ich wiele (jeśli w ogóle) i jestem przekonany, że żadna potencjalna wada nie wpłynie znacząco na wynik.

4 Podejrzewam, że rzeczywisty koszt statycznego typowania realnych, projekty na dużą skalę jest nie istnieje, ponieważ wtedy staje się naturalną częścią architektury, a nawet może ułatwić planowanie. Naprawianie błędów typu statycznego zajmuje dużo czasu, ale znacznie mniej niż błędy wykryte później. Zostało to szeroko przebadane empirycznie i znane od dziesięcioleci (patrz np. Kod Complete ).


3
Wiem, że to późna odpowiedź na to pytanie, ale wierzę, że nowe dowody (które wyjaśniam tutaj) zmieniają całą debatę statyczną vs. dynamiczną.
Konrad Rudolph,

2
To z pewnością interesujące, ale zastanawiam się, jak bardzo odnosi się do konkretnego systemu typów javascript. System typu Python (zwłaszcza python3) jest znacznie bardziej rygorystyczny, a konwersje są znacznie mniej niejawne.
Peter Green

@PeterGreen Tak, to bez wątpienia prawda. Być może mamy szczęście, a podpowiedzi dotyczące rodzaju języka Python doprowadzą do podobnej analizy na późniejszym etapie (choć wątpię, ponieważ wyrażonym celem w PEP484 i PEP526 jest brak implementacji pisania statycznego).
Konrad Rudolph

1
Już czytając streszczenie, mogę już stwierdzić, że metodologia jest zasadniczo wadliwa. Nie możesz użyć bazy kodu napisanej przy użyciu jednej dyscypliny, a następnie po prostu dodać typy, aby uzasadnić argumenty w zupełnie innej dyscyplinie. Kod napisany jako dyscyplina statyczna wygląda zasadniczo zupełnie inaczej niż dyscyplina dynamiczna, nie powinieneś pisać Java w Pythonie, tak jak nie powinieneś pisać Python w Javie. Nawet maszynopis i javascript to zasadniczo inny język, pomimo powierzchownych podobieństw.
Lie Ryan,

2
@LieRyan Jeśli coś, co czyni analizę zbyt konserwatywną, jak zauważono w moim opisie i gdzie indziej. W żadnym wypadku nie unieważnia analizy. Twój 1% szacunek jest, szczerze mówiąc, śmieszny. To kompletnie wyłączone, twoja intuicja zawodzi. Podobnie, twoja charakterystyka problemów z pisaniem statycznym jest typowa dla praktyka pisania dynamicznego, który miał niewielkie rzeczywiste doświadczenie z nowoczesnym pisaniem statycznym (tj. Nie tylko Javą).
Konrad Rudolph

12

Czy bezpieczeństwo typu jest warte uderzenia w szybkość rozwoju i elastyczność?

Tak naprawdę sprowadza się to do tego, co robisz. Jeśli programujesz, powiedzmy, systemy zapasowe dla samolotów, bezpieczeństwo typu jest prawdopodobnie najlepszym rozwiązaniem.

Język dynamiczny a programowanie w języku statycznym to tak naprawdę dwa różne zwierzęta. Oba wymagają zasadniczo odmiennego podejścia. Najczęściej możesz przenieść metodę podejścia między statyczną a dynamiczną, ale stracisz zalety drugiej.

To naprawdę sposób myślenia. Czy jedno jest lepsze od drugiego? To naprawdę zależy od tego, kim jesteś i jak myślisz. Większość ludzi, z którymi pracuję, nigdy nie dotknęliby dynamicznego języka, gdyby nie musieli, ponieważ uważają, że jest za dużo miejsca na błędy. Czy mylą się myśląc o tym? Nie, oczywiście, że nie, ale oznacza to, że zdali sobie sprawę, że ich podejście do stosowania stylu kodowania nie będzie działać w środowisku dynamicznym. Inne osoby, z którymi chodzę do grup użytkowników, są dokładnie przeciwne. Uważają, że pisanie statyczne jest zbyt kłopotliwe, ponieważ ogranicza to ich podejście do rozwiązywania określonych rodzajów problemów.

Mogę szczerze powiedzieć, że często przeskakuję między JavaScript a C #. Teraz znajomość i praca w obu językach w pewnym stopniu wpływa na drugi, ale tak naprawdę kod, który piszę w każdym z nich, wygląda zupełnie inaczej. Wymagają innego podejścia, ponieważ są zasadniczo różne. Przekonałem się, że jeśli myślisz: „Człowieku, jest to o wiele trudniejsze do zrobienia w języku X”, twoje podejście prawdopodobnie trochę się nie zgadza. Oto przykład: ludzie mówią o „Pythońskim” sposobie robienia rzeczy. Oznacza to, że istnieje sposób, w jaki język Python działa, aby ułatwić problem. Wykonanie tego w inny sposób jest zazwyczaj trudniejsze i bardziej kłopotliwe. Musisz pokonać garb wiedzy o tym, jak działa język, aby naprawdę działał dla Ciebie. To'


Przez pewien czas miałem wrażenie, że języki programowania powinny ukrywać tylko te funkcje kodu, o których nigdy nie musisz myśleć. Dotyczy to uzyskania kodu maszynowego aż do czegoś wyższego poziomu, takiego jak Java, ponieważ ten niższy poziom implementacji jest czymś, z czym w zasadzie nigdy nie musisz sobie radzić. Nie dotyczy to typów obiektów. Moim zdaniem pisanie dynamiczne tylko utrudnia programowanie, ponieważ wprowadza całą klasę błędów, które musisz złapać.
MCllorf

7

Niedawno zadane zostało podobne pytanie: języki dynamiczne a statycznie typowane dla stron internetowych

Aby ponownie przedstawić sedno mojej odpowiedzi:

Gdy systemy stają się coraz większe, języki o typie statycznym zapewniają niezawodność na poziomie komponentów, a tym samym elastyczność na poziomie systemu.

Tak, Java jest ściśle wpisana i tak, Java jest do kitu (bez obrazy. Jest okropna. Świetna platforma i ekosystem, ale jeden z najgorszych języków w historii (faktycznie używany)).
Ale wnioskowanie z tego, że ścisłe pisanie jest do bani, jest błędem. To jak wskazywanie na PHP i wnioskowanie o dynamicznym pisaniu do bani (znowu, bez obrazy. Powoli się poprawia, daję ci to).

Osobiście większość mojego rozwoju wykonuję w haXe , który ma system typu statycznego. Jest nie tylko znacznie bardziej wyrazisty niż Java i wymaga znacznie mniej wysiłku z powodu wnioskowania o typie, ale jest również opcjonalny. Jeśli kiedykolwiek stanie Ci na drodze, po prostu ominąć.

Bezpieczeństwo typu jest cechą (jest to coś, co wielu rzekomo na wysokim poziomie języków nie robi się dobrze), aby pomóc Ci uniknąć strzelania sobie w stopę .
I każdy udany dynamicznie typowany język byłby po prostu lepszy, gdybyś miał opcję sprawdzania typu kodu do woli.
Na przykład z pewnością podobało mi się eksperymentowanie z Ruby, ale było tak głównie dlatego, że Ruby jest w pełni zorientowany obiektowo, co jest całkowicie ortogonalne względem obecności systemu typu kompilacji czasu.

Myślę, że twierdzenie, że układy typu statycznego są natrętne, opiera się jedynie na braku wiedzy na temat dobrych układów typu statycznego. Istnieje wiele języków, które robią to dobrze, może być jednym z nich i prawdopodobnie nie jest najlepszy w tym względzie.

Przykładowy kod haXe:

class Car {
    public function new();
    public function wroom() trace('wroooooooom!')
}
class Duck {
    public function new();
    public function quack(at) trace('quackquack, ' + at + '!')
}

function letQuack(o) o.quack();
letQuack(new Car());
letQuack(new Duck());

Spowoduje to błąd czasu kompilacji:

Car should be { quack : Void -> Unknown<0> }
Car has no field quack
For function argument 'o'
Duck should be { quack : Void -> Unknown<0> }
Invalid type for field quack :
to : String -> Void should be Void -> Unknown<0>
For function argument 'o'

Naprawdę nie możesz twierdzić, że włożyłem wiele wysiłku w bezpieczeństwo typu.

Mówienie, że nie potrzebujesz bezpieczeństwa typu, ponieważ masz testy, jest jeszcze bardziej idiotyczne. Pisanie testów jest nudne i powtarzalne. I naprawdę nie chcę pisać testu, żeby się przekonać, że egzemplarz samochodu się nie kwaknie, a kaczka potrzebuje kogoś do kwakania.

Pod koniec dnia przekonasz się, bez względu na to, ile kosztowało cię bezpieczeństwo typu narzutowego, ostatecznie jest ono amortyzowane (nawet w Javie - choć może nie tak szybko).


W Pythonie doctesty są tylko kopiowane i wklejane z repl / shell, jako źródło dokumentacji, a następnie sprawdzane. docs.python.org/3/library/doctest.html
aoeu256

5

Z jakiegokolwiek powodu nie popełniam już błędów związanych z typem obiektu. W językach takich jak C # częściej popełniam błędy związane z rzutowaniami środowiska uruchomieniowego, niż popełniam błąd bezpieczeństwa wykrywalny przez kompilator, który, jak sądzę, jest zwykle spowodowany sporadyczną potrzebą obejścia statyczności statycznej język pisany. Kiedy piszę w ruby, kod dość mocno wskazuje na typ obiektu, a dostępność REPL oznacza, że ​​już eksperymentalnie sprawdziłem, czy istnieje pożądana metoda / atrybuty, lub przeprowadzę test jednostkowy, który w zasadzie to samo, dlatego też rzadko spotykam się z problemami z bezpieczeństwem w Rubim.

Ale to nie znaczy, że statycznie typowane systemy nie mogą być lepsze od nich.

W przypadku języków o typie statycznym bardzo ważny jest również system pisma. Jako przykład, z czymś takim jak monada Some w językach funkcjonalnych (wpisz <Some>: = yes x | no), zyskujesz kontrole czasu kompilacji, które zasadniczo zapobiegają przerażającemu wyjątkowi NullReferenceException powszechnemu w większości systemów typów; po uruchomieniu kodu dopasowującego wzór pojawiają się błędy czasu kompilacji informujące, że nie udało się obsłużyć warunku zerowego (jeśli użyjesz tego mechanizmu do zadeklarowania typu). Redukujesz również podobne typy błędów, gdy używasz rzeczy takich jak |> operator potoku w F #.

W tradycji pisania statycznego Hindleya-Milnera można budować rzeczy, które dają znacznie więcej niż gwarancję, że dany typ twierdzi, że obsługuje interfejs X, a gdy już je masz, powiedziałbym, że system statyczny bardziej wartościowy.

Gdy nie jest to opcja, rozszerzenia Design By Contract do C # mogą dodać kolejny zestaw mechanizmów, które zwiększają wartość systemu typów statycznych, ale nadal wymagają większej dyscypliny niż niektóre z tych paradygmatów funkcjonalnych.


5

To zależy.

Tryby niepowodzenia u ludzi są często statystyczne. Silne sprawdzanie typów zmniejsza prawdopodobieństwo wystąpienia pewnych określonych typów ludzkich awarii (powodujących błędy w kodzie). Ale tylko dlatego, że możesz ponieść porażkę, nie zawsze oznacza to, że to zrobisz (Murphy nie wytrzymuje).

Koszt tego zależy od tego, czy zmniejszenie prawdopodobieństwa potencjalnej awarii jest warte.

Jeśli piszesz kod dla elektrowni jądrowej lub systemu ATC, każda redukcja trybu awaryjnego może być niezwykle ważna. Jeśli szybko prototypujesz jakiś pomysł na stronę internetową, który nie ma specyfikacji i ma prawie zerowe konsekwencje awarii, wówczas ograniczenie trybów awarii lub prawdopodobieństw może, ale nie musi, nic cię kupować, ale może cię kosztować czas programowania (więcej naciśnięć klawiszy itp.), oraz w komórkach mózgowych rozproszonych przez zapamiętywanie wymaganego (-ych) rodzaju (-ów).


3
Twój scenariusz szybkiego prototypowania jest błędny w artykule Paula Hudaka o amerykańskim badaniu marynarki wojennej, które wymagało opracowania podobnej do AEGIS symulacji w różnych językach, z których jednym był Haskell. Spełnia prawie wszystkie kryteria: było to szybkie prototypowanie, wymagania były źle zdefiniowane, a koszt awarii był bliski zeru (jest to niezwykle nieformalny eksperyment). Haskell wyłonił zwycięzcę w każdej kategorii: czas rozwoju, przekroczenie wymagań, wymaganie mniejszej ilości LOC i stworzenie jedynego działającego przykładu wśród wszystkich zawodników!
Andres F.,

2
Artykuł: Haskell vs ..., Experiment in Software Prototyping Productivity - Paul Hudak i Mark P. Jones . Opisuje wyniki eksperymentu zleconego przez ARPA i US Navy.
Andres F.,

Czy zwycięzca Relational Lisp nie był zwycięzcą? Człowieku, chciałbym, żeby były filmy pokazujące ludzi kodujących rzeczy w Lisp z tymi wszystkimi dziwnymi, potężnymi rozszerzeniami, takimi jak Shen (struktura logiczno-relacyjna, która pozwala ci nadawać zależne typy kodowi i mieszać i dopasowywać kod z kodem innym niż typ ), frameworki super-CLOS z predykatem wysyłki itp.
aoeu256

4

W Lisp napisano wiele bardzo skomplikowanych systemów i nie słyszałem, żeby Lisper narzekał, że chcą pisać statycznie. Kiedy z tym pracowałem, nie pamiętam żadnych problemów, które spowolniłyby mnie znacznie, które wychwyciłby statyczny system typów (i można określić typy statycznie we Common Lisp).

Co więcej, główne języki o typie statycznym nie wydają się dobrze przystosowane do wyłapywania błędów. Projektując układ, co ważne jest to, że pewna liczba jest pionowy pomiar na stronie, a nie czy to int, unsigned, float, lub double. Z drugiej strony kompilator często oznaczy konwersje typu, które uważa za niebezpieczne, i na szczęście pozwolę sobie dodać pomiar pionowy i liczbę znaków w ciągu. Ta słabość statycznego systemu typów była oryginalną ideą węgierskiej notacji Simonyi, zanim została skazana na brzydką bezużyteczność.


4

Typy są ograniczeniami dla interfejsów, więc są podzbiorem tego, co możesz chcieć przetestować za pomocą testów jednostkowych, a więc wiele kompromisów jest podobnych:

  • Typy statyczne dają wcześniejsze informacje zwrotne na temat tego, czy kod spełnia wymagania, które mogą być wyrażone przez system typów, w zamian za opóźnienie informacji zwrotnej od zbudowania czegoś minimalnie funkcjonalnego (takiego jak opinia klienta lub testy wyższego poziomu).
  • Wiedza o tym, że kod spełnia określone wymagania, może ułatwić refaktoryzację i debugowanie, ale dodatkowo zwiększa obciążenie związane ze zmienianiem interfejsów i zmienianiem wymagań.
  • W szczególności, jeśli statycznie typowanemu językowi brakuje przymusu, zapewnia on dodatkowe zabezpieczenie przed kodem używanym w danych, który mógłby powodować błędy (zmniejszając potrzebę stosowania warunków warunkowych i asercji), ale zbyt restrykcyjne ograniczenia wymagają od użytkownika napisania więcej kodu, aby zamaskować swoje dane w dopuszczalna forma (np. rzutowanie typu jawnego).
  • Adnotacje typu wyraźnego mogą pomóc w zrozumieniu podczas czytania kodu lub mogą zaśmiecać kod zbędnymi lub niepotrzebnymi informacjami.
  • W zależności od implementacji może to zniekształcić zwięzłość. Zależy to między innymi od tego, czy adnotacje typu są wymagane lub wywnioskowane, od tego, jak dobrze system typów może wyrażać typy ogólne / interfejsy, składnię oraz od tego, czy zamierzasz testować ograniczenia, które mogą być wyrażone przez system typów (tj. ten sam test jest prawdopodobnie bardziej zwięzły jako funkcja językowa niż jako test jednostkowy, ale być może nie zamierzałeś go testować).
  • Dodatkowo (ale niezwiązane z TDD) typy statyczne mogą pomóc w optymalizacji czasu kompilacji, kosztem konieczności sprawdzenia typów (i poświęcenia czasu na ich sprawdzenie i wykonanie optymalizacji), a lepszą optymalizację można przeprowadzić, jeśli dane są ograniczone do typów dobrze odwzorowuje sprzęt. Ułatwia to tworzenie kodu z wymaganiami wydajności, ale może powodować problemy z kodem, który nie pasuje do tych ograniczeń (jak w punkcie 3).

Podsumowując, twierdzę, że języki dynamiczne są szczególnie przydatne do tworzenia prototypów, a jeśli chcesz mieć pewność, że kod jest poprawny, powinieneś faworyzować silny system typów.


3

Tak, zdecydowanie. Jedną rzeczą, którą znajdziesz, gdy używasz zarówno silnie napisanych języków, jak i Python (Python jest silnie napisany), jest to, że najbardziej dobrze napisany kod w językach dynamicznych ma tendencję do przestrzegania wielu takich samych konwencji, jak kod silnie napisany. Pisanie dynamiczne jest bardzo przydatne do serializacji i deserializacji, ale w większości innych rzeczy tak naprawdę nie ma dużej przewagi. A jeśli większość kodu nie jest związana z serializacją, po co wyrzucać bezpłatne sprawdzanie błędów?


4
Języki o silnym typie, takie jak Java i C #, automatycznie przetwarzają deserializację za pomocą Reflection.
Matthieu M.

3

Morgan, mam dla ciebie ciekawy pomysł: pisanie statyczne + dynamiczne. Wspomniałeś o Python, C # i Java. Czy zdajesz sobie sprawę, że istnieją całkiem dobre porty Pythona zarówno dla platformy .NET, jak i Java? W obu przypadkach porty umożliwiają korzystanie z bibliotek tych platform i / lub współdziałanie z istniejącym kodem. Daje to kilka możliwości:

  1. Zachowaj starszy kod w statycznym, nieelastycznym języku. Użyj Pythona do nowych rzeczy.
  2. Używaj Pythona do prototypowania nowych rzeczy na starszych platformach. Ponownie koduj komponenty, które chcesz zachować, w bardziej dojrzałym języku.
  3. Użyj dynamicznego języka do często zmienianych części.
  4. Być może używaj dynamicznego języka do zabawy z pomysłami takimi jak modyfikacja działającego kodu.
  5. Rób wszystko w języku dynamicznym, z wyjątkiem kluczowych części, w których używasz silnie napisanego języka.

Użyłem tych metod już w późnych latach 90-tych, aby ominąć ból związany z rozwojem w C / C ++. Potrzebowałem rodzimych bibliotek, a czasem wydajności. Chciałem jednak lepszej składni, elastyczności, bezpieczeństwa itp. Więc sztuczka polegała na ostrożnym łączeniu ich w celu uzyskania właściwych kompromisów. Często było to w praktyce lepsze niż wyrzucenie całego języka i starszego kodu na inny język / platformę.

(Uwaga: odpowiedź już to powiedziała, ale chcę również ponownie podkreślić dynamiczne pisanie! = Brak / słabe pisanie. Wiele systemów dynamicznego pisania używa silnego pisania od wewnątrz. Sposób, w jaki myślę o tym, co sprawia, że ​​dynamika typów jest taka, że typ zmiennych jest określany w czasie wykonywania, nie wymaga adnotacji typu i / lub może się zmieniać w czasie wykonywania.


2

Nie dostaniesz naprawdę obiektywnej odpowiedzi na to pytanie, ale z mojego doświadczenia wynika, że ​​bezpieczeństwo typu jest nieocenione, dopóki nie opanujesz TDD. Gdy masz już obszerny zasięg testów jednostkowych, w których testy zostały napisane przed kodem, sprawdzanie kompilatora staje się uciążliwe i zaczyna przeszkadzać.


to subiektywna kontrola jakości, więc nic mi nie jest.
Morgan Herlocker

1
Czy ktoś chciałby wyjaśnić głosy negatywne?
pdr

Nie mogę ci pomóc w wyjaśnieniu, ale dałem ci +1, myślę, że jest to użyteczny wkład. Jedną z kluczowych obaw związanych z dynamicznym pisaniem jest to, że dokonasz zmiany gdzieś indziej i złamiesz coś gdzie indziej z powodu założeń, które byłyby egzekwowane przez kompilator w języku o typie statycznym. Ciężki zasięg testu jednostkowego ochroni cię tutaj.
Carson63000,

5
Nie głosowałem za tym, jak napisałeś słuszny punkt, chociaż nie zamierzałem tego urazić, ale twój post okazuje się być małym fanatykiem TDD, i prawdopodobnie jest to powodem, dla którego opinie są negatywne.
Karl Bielefeldt

@Karl, bez obrazy, to było prawdziwe pytanie. Mogę być nieapologicznie pro-TDD, przyznaję
pdr

2

Widzę, że to pytanie się pojawia i myślę, że jakość twojego oprogramowania (i brak błędów) ma więcej wspólnego z twoim procesem programistycznym, z architekturą twojego systemu oraz z zaangażowaniem ciebie i twoich rówieśników w jakość kodu.

Moje ostatnie zadanie polegało głównie na rozwoju Pythona. Pracowałem dla dużej międzynarodowej firmy hostingowej i mieliśmy zespoły programistów w USA, Kanadzie i Korei Południowej. Niestandardowa platforma Python dla aplikacji klienckich, która umożliwia użytkownikom zarządzanie nazwami domen i kontami hostingowymi. Backend: wszystkie python też. Usługa sieci Web Python do komunikowania się z poszczególnymi serwerami w celu wykonania nowej witryny hostingowej, utworzenia nowego bloga, tworzenia wpisów dns w naszym systemie usług nazw; itp. itp. W mojej obecnej pracy aplikacje klienckie są w Javie; naszym głównym produktem jest mieszanka java i flash. Niestandardowa platforma Java dla naszych starszych aplikacji, furtka dla naszych nowych narzędzi wewnętrznych.

Pracując w obu, muszę powiedzieć, że to pytanie mnie wkurza za każdym razem, gdy je widzę. Jeśli używasz dynamicznie pisanego języka i faktycznie testujesz swój kod, nic ci nie będzie. Jeśli system jest dobrze zaprojektowany i przestrzegasz standardów, wszystko będzie dobrze. Nigdy nie było wielu błędów, które pojawiły się z powodu braku typów sprawdzania kompilatora. Większość błędów to błędy logiczne, tak jak dzisiaj moja praca w Javie.


2

Czy bezpieczeństwo typu jest warte uderzenia w szybkość rozwoju i elastyczność? DLACZEGO?

Wpisywanie statyczne to wzrost netto szybkości i elastyczności programowania w całym cyklu życia oprogramowania. Zmniejsza całkowity wysiłek i niedogodności, ale przenosi dużo wysiłku i niedogodności z góry, gdzie jest to bardziej zauważalne. Bariera wejścia w posiadanie działającego kodu jest wyższa, ale gdy przekroczysz tę barierę (przez spełnienie sprawdzania typu), rozszerzenie i utrzymanie tego kodu zajmuje znacznie mniej pracy.

W rozwoju oprogramowania zawsze pojawią się pewne problemy z powodu:

  • Naturalna złożoność tego, co próbujesz osiągnąć

  • Nieodłączna omylność ludzi, zwłaszcza biorąc pod uwagę, że popełniamy więcej błędów, gdy próbujemy zrobić coś bardziej złożonego

Wcześniej czy później musisz poświęcić trochę czasu na rozwiązanie tych problemów. Nie można tego obejść. Pisanie statyczne po prostu rozwiązuje te problemy wcześniej niż później. Wcześniej jest lepiej niż później, ponieważ im później odkryjesz błąd (nie chodzi o to , czy , ale kiedy ), tym więcej kosztuje naprawienie tego błędu.

Naprawienie błędu zgłoszonego przez moduł sprawdzania typu kosztuje znacznie mniej niż koszt debugowania wyjątku związanego z typem zgłoszonego w czasie wykonywania. Odroczenie sprawdzania typu do środowiska wykonawczego po prostu zamiata problem pod dywan.


1

To tylko moja opinia, ale nie, nie sądzę, że bezpieczeństwo typu jest tego warte. Ani przez sekundę.

Od dłuższego czasu jestem programistą. Zaczynając od c ++, c #, a następnie przeniosłem się do javascript (frontend i backend przez node.js). Od czasu, gdy rozwijam javascript, moja produktywność gwałtownie wzrosła, do tego stopnia, że ​​faktycznie pogorszyłem się, używając języków opartych na typach. Jestem również przeciwny kompilacji, chcę, żeby wszystko było teraz w czasie wykonywania. Języki interpretowane to miejsce, w którym uwielbiam programować.

Jeśli chodzi o typy, po prostu nie widzę żadnych korzyści. Teraz widzę typy w taki sam sposób, jak widzę zarządzanie pamięcią. Całkowicie niepotrzebne. Języki jutra powinny całkowicie chronić programistę przed wiedzą o typach. Komputer powinien zrozumieć typy i pominąć programistę.

Oto przykład. Po prostu używałem Swift (nowy język Apple'a), mając nadzieję, że tak naprawdę zadziałałby już dzień temu i spróbowałem: var n = 1/2 nie działało. Myślałem, co tu się dzieje. a potem ze smutkiem zdałem sobie sprawę, że muszę zrobić var ​​n: Float = 1/2. Przypomniało mi to, jak bardzo nienawidzę systemów typu i jak bardzo są to niepotrzebne zaostrzenia.

Zrobiłbym nawet jeszcze jedną milę, mówiąc, że nie chcę nawet typów zdefiniowanych przez użytkownika (takich jak klasy). W ogóle nie chcę typów. Wszystko czego chcę to var i przedmioty. Gdzie dowolny obiekt może być użyty jako dowolny obiekt. A obiekty są dynamiczne i ciągle się zmieniają. Gdzie staje się problemem środowiska wykonawczego, co działa, a co nie.

Programiści lubią mówić, jak luźno pisane języki nie są dobre dla dużych projektów. Ale powiedziałbym, że jest odwrotnie. Silnie pisane języki są przerażające w przypadku dużych projektów. A jeśli powiesz, że javascript nie działa w przypadku dużych projektów, poproś Ubera o ponad 40 miliardów firm, które zarządzają całym backendem na node.js / javascript lub Facebooku, który zaczął z PHP.

Jeśli chodzi o języki wpisywane statycznie, nie jest to dobre dla dzisiejszych szybkich iteracji. oto prosty przykład: masz 10 programistów pracujących nad projektem .net z serwerem ciągłej integracji, jeden programista zgłasza błąd i cała kompilacja jest zepsuta, mimo że 10 programistów pracuje nad różnymi rzeczami, wszyscy są teraz zatrzymani i czekają dla winnego programisty, aby poprawił swój błąd. Mówisz o wydajnym, co? System typów / języki statyczne są w ten sposób współzależne i sprawiają, że kod jest współzależny. Jednak pliki skryptów nigdy nie są od siebie zależne. Jeśli wystąpi problem z jednym ze skryptów, nie zatrzymuje produkcji, wszystkie problemy, które zobaczysz, pozostaną w środowisku uruchomieniowym. A środowisko wykonawcze nigdy się nie kończy. Nigdy się nie psuje. Może produkować nieprawidłowe dane wyjściowe, ale nie daje


1
Dużo „ja”, niezbyt wiele argumentów. A tak przy okazji, czy błąd „psuje się”, kompilacja nie ma nic wspólnego ze statycznym a dynamicznym. Jeśli masz testy jednostkowe, a jeden nie powiedzie się, „Twoja kompilacja jest zepsuta” i mam nadzieję, że nie zostanie wdrożony do produkcji, dopóki nie zostanie to naprawione
nafg

Co sprawiło, że pomyślałeś, że sugerowałem coś takiego?
nafg

Twoja produktywność w javascript nie wzrosła gwałtownie, ponieważ w javascript brakowało typów. Twoja produktywność gwałtownie wzrosła, ponieważ C ++ i C # to ciężkie języki. Typy Javascript + spowodują, że Twoja produktywność gwałtownie wzrośnie. Nikt nie powiedział, że javascript jest niemożliwy dla dużych projektów. JavaScript w dużych projektach jest z pewnością możliwy. Nie jest to jednak idealne. Testy jednostkowe zajmują miejsce sprawdzania typu, również testy jednostkowe mają ograniczony zasięg typu, podczas gdy sprawdzanie typu ma 100% zasięgu.
Brian Yeh

1
@BrianYeh c ++ i c # to ciężkie języki, ponieważ koncentrują się na typach. Właśnie zacząłem używać Reagjs w mojej pracy i moja wydajność ponownie spadła z powodu ciągłego używania typów i komponentów. jeśli lubisz typy i testy jednostkowe, dobrze dla ciebie. nie każdy z nas podziela ten styl programowania.

1
@foreyez reagjs nie ma typów. Prawdopodobnie masz na myśli przepływ. Testy jednostkowe zastępują sprawdzanie typu, więc jeśli nie masz sprawdzania typu, potrzebujesz więcej testów jednostkowych. Testy jednostkowe i typy są siłami przeciwnymi. Zmniejszenie produktywności jest iluzją. Każdy błąd typu wykryty w języku bezpiecznym dla typu jest błędem, który nie został wyłapany w języku dynamicznym. Wydaje się tylko szybciej. Bezpieczny język typu zmusza cię do zaradzenia tym błędom z góry.
Brian Yeh

0

TAK.

Pracowałem w aplikacjach PHP, w których typy nie są tak „mocne” jak w Javie lub C #. Zazwyczaj kończyłem „symulowanie typów”, ponieważ w celu uniknięcia złych automatycznych konwersji lub sprawdzania poprawności danych.

Języki dynamiczne są dobre dla skryptów systemu operacyjnego i szybkich małych aplikacji., A nie złożonych aplikacji.

Podsumowanie: Jeśli muszę wybrać język programowania „Słaby typ” lub „Typ dynamiczny” lub język programowania „Silny typ” dla złożonej aplikacji biznesowej, wybieram język programowania „Silny typ” .


0

Myślę, że warto cofnąć się o krok i rozważyć, kiedy dynamiczne pisanie powoduje problemy.

Jednym z przypadków jest to, że gałąź kodu w ogóle nie jest testowana, ale szczerze mówiąc, kod, który nigdy nie jest testowany, może być wadliwy, niezależnie od tego, czy używane jest dynamiczne pisanie.

Innym bardziej subtelnym problemem jest niedoskonała zastępowalność.

Jeśli typ jest po prostu całkowicie niepoprawny, to chyba że nie zostanie użyta określona ścieżka kodu, która prawdopodobnie zostanie szybko wykryta.

Z drugiej strony, jeśli typ jest niedoskonałym zamiennikiem, wówczas kod może przeważnie działać, ale łamać się w subtelny sposób, który zostanie wykryty dopiero później.

Dwa najczęstsze typy programowania to liczby i ciągi znaków. W wielu dynamicznych językach są one niedoskonałymi substytutami. Na przykład javascript lub php, jeśli podasz liczbę, w której spodziewany jest ciąg znaków lub odwrotnie, twój program działa bez zgłaszania błędu, ale może źle zachowywać się w subtelny sposób.

Python uniknął tego konkretnego problemu, liczb i ciągów znaków w żaden sposób nie zastępuje się nawzajem, a próba użycia jednego tam, gdzie oczekuje się drugiego, zwykle prowadzi do szybkiej awarii.

Jednak nie uniknął całkowicie problemu niedoskonałej podatności. Różne typy liczb mogą być niedoskonałymi substytutami, podobnie jak różne typy sekwencji.


Dostaję tutaj, że nie sądzę, że można porównywać korzyści i koszty pisania statycznego i dynamicznego w sposób ogólny, ponieważ uważam, że zarówno korzyści, jak i koszty zależą od konkretnej odmiany pisania statycznego lub dynamicznego w języku wykorzystuje.

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.