Coś dla nieprzekonanych do dynamicznego typowania

Natrafiłem dzisiaj na artykuł Bruce’a Eckela

Strong Typing vs. Strong Testing
. Autor, znawca języków programowania,
znany autorytet w tej dziedzinie (autor słynnej książki Thinking in
Java
), opisuje w nim jak przekonał się do dynamicznego typowania
mimo, że wcześniej za jedyne słuszne uznawał statyczne systemy typów.
Oczywiście język z dynamicznym typowaniem, którym się zachwyca, to Python.
Interesująca jest też kontynuacja
tematu
— odpowiedź na list profesora, który z poprzednim artykułem
się nie zgadza. Blog Bruce’a
Eckela
dodałem do linkowni — czuję, że będę tam często zaglądał.

Miłe jest, że do Pythona przekonuje się coraz więcej znawców poważnych
języków
i miłe jest, że potrafią opisać czemu Python jest taki dobry
— zawsze to kolejne argumenty do przekonania nieprzekonanych. Co do
statycznego typowania, to też nie uważam tego za coś niezbędnego, ale raczej, że
w większości przypadków przeszkadza, jednak nie jestem też przeciwnikiem
wprowadzenia takich, opcjonalnych oczywiście, rozszerzeń do Pythona. Dobrze
czasem jest mieć możliwość zaznaczyć w kodzie dla jakich argumentów jest on
przygotowany. Często jest to istotna informacja dla innych developerów (ale tu
wystarcza odpowiednia dokumentacja) i dla interpretera/kompilatora (pozwala na
lepszą optymalizację krytycznych elementów kodu). Problem polega na tym, żeby
wprowadzić to nie psując przejrzystości i elastyczności języka i aby nie było
to nadużywane.

16 uwag do wpisu “Coś dla nieprzekonanych do dynamicznego typowania

  1. Taaa, Eckelowi ostatnio się trochę poprzestawiało. Oprócz statycznego typowania wziął sobie na cel sprawdzane wyjątki w Javie, bo niby strasznie komplikują kod. Jak się ich nie umie stosować, to faktycznie komplikują, a jak ktoś słyszał o łańcuchach wyjątków, to okazuje się, że wszystko jest proste i eleganckie.<br><br>
    Co do dynamicznego typowania, to używając często PHP muszę przyznać, że bardzo cierpię z powodu braku statycznego typowania. Mam jakąś funkcję/metodę w klasie, to zanim jej użyję, muszę sprawdzać print_r(…), co ona właściwie zwraca , podobnie trzeba się szarpać z argumentami.<br><br>
    Oczywiście sprawę załatwia dokumentacja, tylko, po pierwsze musi być, a jeśli sami coś robimy, to musimy ją sami napisać. I tu jest zabawna rzecz. W Javie JavaDoc sam nam wygeneruje dokumentację dotyczącą typów argumentów i zwracanych wartości. W Pythonie jak te świstaki, zamiast kod pisać, to dziergamy dokumentację. Zmienimy argumenty w metodzie, to w Javie JavaDoc automatycznie to uwzględni, a w Pythonie? Poprawiamy sami, chyba, że zapomnimy<br><br>
    Kolejna sprawa, to fakt, że dynamiczne typowanie jest często fikcją, o czym można się łatwo przekonać definiując w Pythonie 'tuple' z jednym elementem, robimy to tak:<br>
    <pre>mojatupla = 'hello',</pre><br>
    warto zwrócić uwagę na przecinek na końcu, to on wskazuje, że mamy do czynienia nie ze Stringiem a z Tuplą. Ja już wolę oznaczać typ zmiennej słowem kluczowym, niż przecinkiem, ale to już kwestia gustu.<br><br>
    Wielu ludzi zapomniało, po co Java została utworzona. Nie tworzone jej, żeby można było w niej pisać programy szybko. Stworzono ją po to, żeby można pisać w niej niezawodne programy, po to statyczne typowanie, wyjątki, maszyna wirtualna itp.<br><br>
    W Pythonie, żeby można mieć zaufanie do programu, to trzeba napisać kilobajty testów jednostkowych. W Javie też pisze się bardzo często testy jednostkowe (tam to już jest standard), ale przynajmniej nie trzeba napisać tego tyle, co w Pythonie, bo wiele rzeczy po prostu sprawdza kompilator. I znowu w Javie piszemy kod, a Pythonie odwalamy robotę kompilatora.<br><br>
    Z tymi modami na języki programowania, to trzeba uważać… 🙂

    Polubienie

  2. „Mam jakąś funkcję/metodę w klasie, to zanim jej użyję, muszę sprawdzać print_r(…), co ona właściwie zwraca , podobnie trzeba się szarpać z argumentami.”

    To tylko źle świadczy o bibliotece która udostępnia tę funkcję. To co ona zwraca powinno być oczywiste (istnieją pewne konwencje), albo opisane w dokumentacji lub w przykładach.

    „Kolejna sprawa, to fakt, że dynamiczne typowanie jest często fikcją, o czym można się łatwo przekonać definiując w Pythonie 'tuple' z jednym elementem, robimy to tak:
    mojatupla = 'hello',”

    1. Co to ma do dynamicznego typowania? Odbiedy coś może ze słabym typowaniem, ale właściwie to kwestia składni.
    2. To powinno być: mojatupla = ('hello',)
    (to że się da inaczej, to wynika ze "specjalnego przypadku", który jest przydatny w innych sytuacjach)

    „W Pythonie, żeby można mieć zaufanie do programu, to trzeba napisać kilobajty testów jednostkowych. W Javie też pisze się bardzo często testy jednostkowe (tam to już jest standard), ale przynajmniej nie trzeba napisać tego tyle, co w Pythonie, bo wiele rzeczy po prostu sprawdza kompilator”

    Załóżmy, że mamy funkcję, która ma mnożyć dwie liczby całkowite:

    Żeby to dobrze sprawdzić w Javie należałoby w testach uwzględnić mnożenie jakichś charakterystycznych liczb, np.:

    funkcja(0,0) == 0
    funkcja(5,0) == 0
    funkcja(5,1) == 1
    funkcja(5,5) == 25
    funkcja(5,-5) == -25
    funkcja(-5,-5) == 25

    Ten zestaw testów sprawdzi najważniejsze cechy mnożenia.
    A w Pythonie? W Pythonie będzie dokładnie taki sam zestaw testów. Bo sprawdzamy tę samą funkcjonalność. Jeśli program jest poprawny, to poprawnie wykonuje to czego od niego chcemy. W Javie najwyżej część błędów wykryłby już kompilator, ale dopiero zestaw testów może zaświadczyć o poprawności programu. W Pythonie żaden dodatkowy test z powodu dynamiczności nie jest potrzebny.

    A teraz potrzebujemy funkcję mnożącą dwie liczby zmiennoprzecinkowe…

    W Javie trzeba napisać nową funkcję (prawdopodobnie przy użyciu cut&paste) i nowy zestaw testów do niej.

    W Pythonie wystarczy dopisać testy dla argumentów rzeczywistych i poprawić odpowiednio tę funkcję, żeby z nowymi testami też działała. Najprawdopodobniej nic nie będzie trzeba poprawiać. Dla liczb zespolonych też nie.

    To oczywiście bardzo prosty przykład, ale tak podobnie to działa dla większych projektów.

    Polubienie

  3. mmazur: nie. W ogóle wiele o nim nie wiedziałem. Słyszałem o Thinking in Java, o Thinking in C++, które podobno od tego pierwszego gorsze… i tyle. Dopiero jak dzisiaj trafiłem na te artykuły, to dowiedziałem się coś więcej i chyba polubiłem gościa 🙂

    Polubienie

  4. Troszkę dziwią mnie przykłady Eckela. Narzeka on na konieczność zachowania zgodności poprzez rzutowanie w górę i że jest to czaso/pracochłonne i mu się cykle marnują. Z całą pewnością jest autorytetem w dziedzinie programowania (TIJ jest świetnie napisana), ale mam podejrzenie, że nie tworzył nic dużego w PHP – z całą pewnością doceniłby upcasting. Z resztą, nie trzeba od razu budować klas, wystarczyłby mu
    interface Gadatliwy { public void gadaj() throws Chrypa; }
    oraz class Dog implements Gadatliwy.

    Silne typy są nie do przecenienia. Doceniam to ilekroć zastanawiam się czy metoda zwróci NULL, FALSE czy array(). A siedzimy przecież z co-koderem dwa metry od siebie i wystarczy zapytać. Tylko pytać trzebaby było co chwilę i tu widać, że siła dobrego języka i środowiska polega nie tyle na udostępnianiu jakiejś killer-funkcjonalności, tylko eleganckim i wygodnym połączeniu drobnych udogodnień jak wyjątki, silne typy, interfejsy, iteratory, itd.

    Czekając z utęsknieniem aż przeniosą mnie w firmie na PHP5 wyglądam w kierunku następnych wersji, w których chętnie widziałbym _obowiązkowe_ silne typy z _możliwością_ zrelaksowania ich ogólnym typem mixed lub object.

    Polubienie

  5. Jeśli interesuje cię rozróżnienie na NULL, False i pustą/pełną tablicę, to znaczy, że język jest okdr. W pythonie zawsze po prostu piszę if not cośtam.

    I owszem, statyczne typowanie pewnie czasami jest przydatne, ale nie w standardowych zastosowaniach, gdzie znacznie wygodniejsze są odpowiednie konstrukcje języka + standardowe operatory jakie można przeciążać przy obiektach (iteracja, odwołanie do elementu, sprawdzanie czy pusty, etc. etc.).

    Polubienie

  6. mmazru: pisanie zawsze „if not cośtam” niekoniecznie jest dobrym pomysłem. Brak napisu i napis o długości 0 to dwie różne sprawy. Więc, jeśli interesuje Ciebie czy coś jest None, to piszesz „if cośtam is None”. Przy okazji to będzie szybsze.

    Ale jeśli nie jest oczywiste, czy funkcja zwraca NULL, False, czy pustą tablicę, to gdzieś jest problem. A jeżeli podobna rozterki pojawiają się co chwilę, to znaczy że jest bardzo duży problem z konkretnym API — jest niekonsekwentne i niedodokumentowane. Nawet przy ścisłej, statycznej kontroli typów tak utrzymywane API będzie powodować problemy. Bo jeśli będziemy nawet mieli podane na „tacy” że argumentem jest tablica napisów, to niekoniecznie z tego wynika co te napisy oznaczają. Poza tym, zadaniem kompilatora/interpretera nie jest przecież wymuszanie dokumentacji.

    Polubienie

  7. mmazur, Jajcus: PHP jest okdr. W tym konkretnym przypadku jest nawet bardzo. Nawet gdyby przyszedł jakiś faszysta i określił jasno API, to i tak łowienie błędów będzie utrudnione, no bo przecież wg. interpretera PHP array("ściema") == TRUE, itp. A tu właśnie chodzi o testowanie i poprawianie – gdzie przyszła zła dana, która przeleciała przez pół systemu i zabiła proces Postgresa.
    Dlatego czekam na type hinting w PHP5.
    A poza tym lubię ten język mimo jego fatalnych braków i felerów. Dzisiaj np. potrzebowałem użyć statycznej zmiennej składowej – Rasmus, Zeev i Andi musieli byś ostro pijani gdy to projektowali.
    mmazur: Zgodzę się, że dynamiczne typowanie może być przydatne. Również jestem zdania, że słabe typowanie należy stosować tylko tam, gdzie jest to absolutnie niezbędne, ew. gdy oszczędzamy sporo kodu i staje się on czytelniejszy. W projekcie, który liczy (clickety click, grep grep) 1790 klas to prawdziwa udręka przy debugowaniu.

    Polubienie

  8. 1790 klas? A to oby na pewno sens trzymać to wszystko w jednej aplikacji? Bo jeśli przyjąć założenie, że beztypowość pythona powoduje, że nadaje się on co najwyżej do aplikacji średniej wielkości, to wniosek jest automatycznie taki, że python zniechęca do tworzenia zajebiście dużych monolitów. I to jest prawdę mówiąc good thing.

    Polubienie

  9. A ja dziś w pracy wklepałem w Intranecie komentarz do zadania: "Jeszcze jedno zadanie z PHP i zastrajkuję". Jestem tam, do diabła, zatrudniony jako programista Java! Czy to oznacza że jestem taki genialny, że wszystko zrobię w każdym języku? :>

    Polubienie

Co o tym sądzisz?