Dzisiaj będzie trochę dziwny post. Temat niby techniczny, ale nie mam zamiaru pokazywać tu kodu źródłowego, benchmarków itp.
Swoją przygodę z programowaniem zacząłem od wysokopoziomowych, dynamicznie typowanych języków (php, python, (trochę) ruby itd.). Czy to dobrze czy źle, trudno mi powiedzieć. Na dzień dzisiejszy wiem jednak, że nie wierzę w przyszłość kompilowanych, statycznie typowanych języków (jak c czy c++). Dlaczego? Ponieważ uważam, że niedługo system operacyjny oraz programy przez nas uruchamiane zmienią się diametralnie. Nie będziemy instalować programów na dysku, ale uruchamiać je w przeglądarce. System operacyjny będzie tylko łączył się z internetem oraz udostępniał przeglądarkę. Tam, czyli w aplikacjach webowych, używanie języków takich jak c++ jest kompletnie bez sensu (chociaż widziałem framework webowy dla c++ o.O). Temat ten rozwinę w innym poście, dzisiaj miało być o statycznym typowaniu :)
Teraz potrzebne będzie trochę wyobraźni (mówiłem, że dzisiejszy post będzie nietypowy, prawda?).
Wyobraźmy sobie szafę, w której mamy szuflady. W niektórych mamy bieliznę, w innych spodnie, w jeszcze innych koszule itd. Jeżeli chcemy wiedzieć co się w danej szufladzie znajduje, po prostu zaglądamy do niej. Z czasem nie musimy już zaglądać do każdej szuflady, pamiętamy już co znajduje się w każdej z nich.
Podobnie jest ze zmiennymi. Jeżeli chcemy wiedzieć co się w niej znajduje po prostu do niej zaglądamy ( zmienna = "costam" - o! ta zmienna zawiera string!). Dzięki odpowiednim nazwom, pamiętamy też co się w danej zmiennej znajduje ( lista_artykulow = ['jedzenie', 'picie', 'proszek do prania'])! Nie potrzebna jest więc nikomu informacja o typie zmiennej!
Tak wiem, że typujemy zmienne nie dla siebie, ale dla komputera. Dlaczego jednak twórcy niektórych języków programowania bardziej martwią się o dobro komputera niż o dobro programisty?!
Pytanie zasadnicze: czy zawsze (!) zaglądasz do każdej zmiennej, kiedy chcesz jej użyć? A zmienne właśnie typujemy dla siebie, żeby ograniczyć ilość głupich błędów popełnianych przez człowieka. Takie samo zadanie mają wszelkie modyfikatory „const”, „final”, itp. A że komputer (kompilator) przy okazji potrafi to wykorzystać do optymalizacji, to inna sprawa.
OdpowiedzUsuńStatyczne typowanie jak najbardziej dba o dobro programisty. Dlatego kompilator jest w stanie pokazać błędy programisty, ew. wskazać podejrzane miejsca w kodzie. Nie mówiąc już o tym co może zrobić dla programisty dobre IDE w którym piszemy kod. Języki statycznie typowane, były i będą, są po prostu do innych zastosowań (jak każde narzędzie).
OdpowiedzUsuńStatyczne typowanie i ścisła kontrola typów ma swoje zalety. Jedną z nich jest jednoznaczność. Weźmy na przykład taki kod javascriptowy:
OdpowiedzUsuńvar z="1";
z=z+1;
co będzie zawierać zmienna z? 2? Czy może "11"?
A to, że większość języków używana w technologiach webowych nie ma typowania wynika według mnie stąd, że przytłaczająca większość danych przetwarzanych w takich aplikacjach to albo stringi, albo ich kolekcje.
MCV: Najczęściej pamiętam, że zmienna title to string, a articles to słownik ;)
OdpowiedzUsuńŁukasz: Przecież interpreter też pokazuje błędy (te związane z typami też!). Oczywiście mówię tu o Pythonie/Rubym bo np. PHP zmienia sobie typy jak chce :/ IDE dla dynamicznie typowanych języków też potrafią wiele zdziałać ;)
Czesiu: Ścisła kontrola typów - oczywiście! Bo inaczej wychodzą takie kwiatki - http://zestyping.livejournal.com/124503.html.
Ja akurat zgadzam się z Krzysztofem. Język sam powinien wykryć "typ zmiennej" zatem:
OdpowiedzUsuń$a=1
$a+$a=2 a nie 11.
Im bardziej komputery będą "rozumować jak ludzie" tym lepiej.
Dosyć ograniczone spojrzenie. Zarówno typowanie statyczne jak i dynamiczne ma swój sens. Nie ma jednego słusznego typowania. Typowanie statyczne ma swój narzut (np. zwiększa ilość kodu do napisania), ale im większy projekt tym bardziej to się zwraca. Typowanie dynamiczne bardzo dobrze sprawuje się w średnich i mniejszych aplikacjach (co nie znaczy, że nie da się pisać wielkich aplikacji). Typowanie statyczne pozwala na łatwiejszą refaktoryzację (wręcz niekiedy automatyczną), lepsze wspomaganie GUI. Można tak wymieniać dosyć długo, ale wniosek powinien być taki jak już napisałem: nie ma jednego słusznego podejścia. Osobiście uważam, że przyszłość to łączenie tych dwóch różnych podejść. Przykładem jest łączenie javy z jrubym, jythonem, albo c# z IronRuby, IronPython. Część aplikacji piszemy w języku statycznym, a część w dynamicznym.
OdpowiedzUsuń"Lepsze wspomaganie GUI" - chodziło mi oczywiście o IDE (podpowiadanie kodu, dopisywanie kawałków kodu, znajdywanie błędów (już na poziomie pisania a nie kompilacji).
OdpowiedzUsuńKrzysztof: ja też pamiętam, do czasu kiedy piszę również z innymi programistami. Swoje każdy pamięta, innych jakby mniej.
OdpowiedzUsuńA gdy interpreter pokazuje błąd, to może być już za późno. :-)
„Im bardziej komputery będą "rozumować jak ludzie" tym lepiej.”
Ha. Tym gorzej, bo różni ludzie rozumują inaczej. Komputery mają się zachowywać przewidywalnie. :þ
CZESIU Twój przykład nie ma nic wspólnego z typowaniem statycznym. Tutaj poruszyłeś inną kwestię, mianowicie typowania słabego/mocnego (http://en.wikipedia.org/wiki/Strongly-typed_programming_language i http://en.wikipedia.org/wiki/Weak_typing).
OdpowiedzUsuńMCV: "A gdy interpreter pokazuje błąd, to może być już za późno." Nie za bardzo to rozumiem:
OdpowiedzUsuńPiszę program -> kompiluje -> wyrzuca mi błąd -> poprawiam -> kompiluję bez błędów -> uruchamiam
Piszę program -> uruchamiam -> interpreter wyrzuca błąd -> poprawiam -> uruchamiam
Piszesz program -> nie dotestujesz czegoś (bo masz dużo na głowie) -> uruchamiasz na produkcji -> klienci widzą jak im się sypie. Bo zrobiłeś literówkę, albo coś tego rodzaju.
OdpowiedzUsuńDlaczego jednak twórcy niektórych języków programowania bardziej martwią się o dobro komputera niż o dobro programisty?!
OdpowiedzUsuńGdyż co wygodniejsze dla ludzi, to jest wolniejsze. Sory, ale taka prawda. I ostatnio zauważyłem tendencję do skrajności, np. .NET, czy Java... Gdy widzę, że aplikacja jest napisana w pierwszym, czy drugim, to wolę poszukać odpowiednika napisanego z wykorzystaniem natywnych mechanizmów. Poza tym, zauważam tendencję dokładnie odwrotną do Twojego stwierdzenia.
Dlaczego? .net: ktoś napisze pierdołę w najnowszym frameworku i muszę ściągać kilkadziesiąt MiB danych, zmarnować kilkaset tylko po to, aby zadziałał program o wadze kilkunastu KiB.
Java: owszem, wygodny dla programistów, ale z wydajnością nie ma nic wspólnego. Wszyscy zachwalają sobie np. Eclipse i różne dodatki do niego, natomiast ja omijam szerokim łukiem ze względu na ospałość w działaniu...
Możecie ględzić, że sieję herezje, ale przypomnijcie sobie czasy demosceny sprzed 15 lat... Ludzie się dwa razy zastanawiali, czy dana zmienna jest potrzebna, czy nie, co było dobre, a już nie jest.
Ja akurat zgadzam się z Krzysztofem. Język sam powinien wykryć "typ zmiennej" zatem:
A typowanie zmiennych jest dobre, gdyż oszczędza pamięć - np. liczba "123" zapisana w stringu zajmuje 3 bajty podczas, gdy z wykorzystaniem inta tylko jeden.
PS. ~autor: okienko treści komentarza jest IMHO za małe.
I dzięki takiemu podejściu w PHP (0 == "cokolwiek") zwróci true
OdpowiedzUsuńWujciol: Dynamiczne typowanie != słabe typowanie!!! Spójrz co napisał Radarek kilka komentarzy wcześniej.
OdpowiedzUsuńWiem
OdpowiedzUsuńWeźmy prosty przykład - chcemy program, który wczytuje dwie dane, po czym je sumuje i zwraca wynik. Żeby nie było wątpliwości, że kwestia jest w statyczności/dynamiczności, a nie w słabości/silności typowania, załóżmy że nasz język jest najsilniej typowany jak tylko się da - 0 automatycznych konwersji typów.
OdpowiedzUsuńZarys programu (żeby się nie zagłębiać w szczegóły implementacyjne) może wyglądać tak:
a = wczytajDaną();
b = wczytajDaną();
c = a + b;
return c;
Proste, prawda? No niekoniecznie, bo oczywiście programiści popełniają błędy. Powiedzmy, że nasz kolega piszący funkcję wczytajDaną spartolił robotę i zapomniał o rzutowaniu/zamianie na inta gdzieś tam w kodzie, przez co jego funkcja nieoczekiwanie zwraca stringa.
(I) Język z dynamiczną kontrolą typów
Kompilacja (o ile w ogóle występuje) nic nie wykryje. W trakcie interpretacji/wykonania też nie dostaniemy żadnego komunikatu o błędzie, jeśli tylko język ma przeładowany "+" dla stringów. Efekt będzie taki, że zamiast zsumowanych liczb zwrócimy skonkatenowane stringi. W dodatku jeśli w końcu zauważymy, że program działa źle, zlokalizowanie, że problem leży w funkcji wczytajDaną z pewnością nie będzie oczywiste.
(II) Język ze statyczną kontrolą typów
Kompilator już na samym początku zauważy błąd - funkcja ma zwracać inta, a zwraca string. Gdyby jakimś cudem nie zauważył, to zwróci na to uwagę w co najmniej kilku innych miejscach - do zmiennych intowych a i b przypisujemy stringi, później do intowego c też, a na końcu sami zwracamy string zamiast inta. Każdy kawałek kodu świeciłby błędem. Co więcej zlokalizowanie przyczyny jest banalnie proste - kompilator najczęściej wskazuje konkretną linijkę, w której wystąpił błąd.
Wiem, że przykład jest naiwny. Ale każdy popełnia błędy, a w swojej praktyce programistycznej nieraz spotykałem się z tak idiotycznymi pomyłkami - zarówno swoimi, jak i cudzymi - że w tej materii jestem w stanie uwierzyć praktycznie we wszystko.
Patrząc bardziej szowinistycznie na sprawę, to zalety dynamicznego typowania są naprawdę mizerne - wygodę pisania kodu w pełni niweluje wygoda debuggowania kodu typowanego statycznie. W pewnych - z mojego punktu widzenia rzadkich - przypadkach pozwala na nieco większe możliwości. Za to po stronie typowania statycznego stoi szybkość, przewidywalność bezpieczeństwo i większa kontrola nad kodem. Języki typowane dynamicznie nie są nowością - Perl istnieje od ponad 20 lat, przed nim też były inne. Ale z jakiegoś powodu języki dynamicznie typowane nie zawojowały w dalszym ciągu świata większych programów desktopowych. Osobiście nie znam żadnego systemu operacyjnego, pakietu biurowego czy przeglądarki internetowej pisanej w dynamicznie typowanym języku. Oczywiście, języki dynamiczne nieźle się sprawdzają w pewnych zastosowaniach - do pisania skryptów czy aplikacji webowych, ale to nie jest i nigdy nie będzie cały świat informatyki. Czy wobec tego dalej uważasz, że "statyczne typowanie jest bez sensu"?
Notabene, stwierdzenie "Tam, czyli w aplikacjach webowych, używanie języków takich jak c++ jest kompletnie bez sensu" jest bardzo mocno ryzykowne, polecam zapoznanie się z JSP.
typowanie statyczne jest bardzo dobre bo znajduje czasem ciezkie do wytropienia błędy...
OdpowiedzUsuńpo za tym takie języki jak C++ (kompilowane natywnie) dzięki typowaniu wiedzą ile bajtów pamięci przerzucić na stos i robią to od razu, dzięki czemu są bardzo szybkie. C++ podczas wykonania nie zastanawia sie co siedzi w zmiennej - ten typ ma np 4 bajty (int) - rzuca instrukcja assemblera push 4 razy te cztery bajty i zmienna juz jest.
A taki php najpierw musi sobie zapisac zmienna w swojej tablicy, sprawdzic jej typ, wykonac odpowiednie konwersje.. a czas leci.. ciezko powiedziec ile instrukcji assemblera to będzie ale myślę że rząd wielkości więcej niż w C++.
Przyznam szczerze, że przez te prawie 3 lata trochę zmieniło się moje podejście ;) Ale dalej uważam, że takie statyczne typowanie jak w C/C++ czy Javie jest zupełnie bez sensu. Dlaczego? Ano dlatego, że można stworzyć język który będzie przyjemny dla programisty a jednocześnie pod spodem będzie się zachowywał tak (i tak samo szybko działał) jak język statycznie typowany. Świetnym przykładem jest tutaj Scala, która jest co prawda statycznie typowana, ale posiada inferencję typów. To znaczy, tam gdzie kompilator może odgadnąć typ zmiennej (czy tego co zwróci funkcja) tam nie musimy tego explicite zaznaczać. Oczywiście czasem jest taka potrzeba - przy bardziej skomplikowanych funkcjach. Bardzo przydaje się jednak (i teraz czasami mi tego np. w Rubym brakuje) określania typu parametrów funkcji - tego Scala wymaga (tzn. nie możemy tego **nigdy** pominąć).
OdpowiedzUsuńDa się więc stworzyć język który ma i zalety języka statycznie typowanego (wsparcie IDE, lepsze działanie kompilatora, mniejsza podatność na błędy) i języka dynamicznie typowanego (nie musimy pisać bez przerwy rzeczy **oczywistych** - https://gist.github.com/1474405)
Szczerze? Co mnie przy dzisiejszych komputerach obchodzą 4 bajty ;)
Odnośnie ostatniego komentarza: C++11 też ma inferencję typów: magiczne słowo "auto", które właśnie zmieniło znaczenie. Teraz już można np. robić tak:
OdpowiedzUsuńfor (auto x: { -3_dB, 0_dB, 3_dB, 6_dB })
...
Podobnie z lambdami, gdzie nie trzeba explicite podawać zwracanego typu. A jeszcze inny ciekawy przykład to język Pike, który jest dynamicznie typowany, ale można nakładać ograniczenia do typów zmiennych. I kompilator będzie sprawdzał typy przy kompilacji tam, gdzie zostały określone, a jeśli zajdzie potrzeba, to można sobie pofolgować i napisać coś w mniej restrykcyjny sposób. :-)
Przyydatne to było!
OdpowiedzUsuńCzy bez silnego typowania możliwe byłoby używanie tablic asocjacyjnych (bez których nie wyobrażam sobie pisania w PHP)? Moim zdaniem to jest główna zaleta typów dynamicznych.
OdpowiedzUsuńDobrze opisane
OdpowiedzUsuńOgólnie mi jako laikowi programowania takie dane nie za wiele mówią i statyczne typowanie brzmi dla mnie troszkę jak wiedza magiczna. Zapewne dla profesjonalistów z branży IT jak https://craftware.pl nie byłoby problemów z odpowiedzią na to pytanie, gdyż to w końcu jest ich praca i tym się zajmują na co dzień.
OdpowiedzUsuńŚwietnie napisane. Pozdrawiam serdecznie.
OdpowiedzUsuń30 year-old Research Nurse Mordecai Ferraron, hailing from Sioux Lookout enjoys watching movies like Divine Horsemen: The Living Gods of Haiti and scrapbook. Took a trip to Zollverein Coal Mine Industrial Complex in Essen and drives a Sierra 1500. kliknij zasoby
OdpowiedzUsuń