Reviews — mina86.comhttp://mina86.com/atom/cat/reviews/content/html/2010-01-31T14:04:15ZMichał ‘mina86’ Nazarewiczhttps://mina86.comPython, wrażeniahttp://mina86.com/2010/01/31/python-wrazenia2010-01-31T14:04:15Z2010-01-31T14:04:15ZMichał ‘mina86’ Nazarewiczhttps://mina86.com<p>Niedawno miałem okazję stworzyć trochę kodu w Pythonie. Popisałem sobie w nim kilka dni i muszę przyznać… język jest tragiczny, zastanowię się kilka razy zanim po raz kolejny go użyję.<p><small>Wpis ten dedykuję pewnej osobie, która ciągle mi przypomina, abym pisał nowe wpisy. :)</small><h2>Wcięcia</h2><p>Zacznę powolutku, od kwestii raczej mało istotnych, wręcz błahych, zatem na początek może o wcięciach. Jak niektórzy pewnie wiedzą, Python wyróżnia bloki za pomocą wcięć, czego efektów jest kilka.<p>Po pierwsze edytorowi tylko czasami udaje się zgadnąć poziom wcięcia. W „zwykłych” językach, wystarczy dopasować do siebie klamerki (czy inne wyznaczniki bloku), aby móc bezbłędnie wskazać, w którym miejscu powinien zaczynać się tekst. Gdy jednak blok jest wyróżniony wcięciem, to w najlepszym wypadku, edytor będzie pozwalał na wielokrotne wciskanie taba, co spowoduje skakanie pomiędzy możliwymi poziomami wcięć.<p>Po drugie, choć to może kwestia przyzwyczajenia, ale zmiana poziomu zagnieżdżenia dla większych fragmentów kodu jest zadaniem nietrywialnym.<p>Po trzecie, jak powszechnie wiadomo „najlepszym” sposobem debugowania jest dodanie printów wewnątrz kodu. Mam zwyczaj pisać je od początku linii, dzięki czemu rzucają się w oczy i łatwo je potem usunąć. W Pythonie coś takiego nie przejdzie — wywołania muszą być wyrównane, co skutecznie komplikuje późniejsze wyczyszczenie z nich kodu.<h2>Upośledzona lambda</h2><p>Pozostając jeszcze w strefie składni i wcięć, warto wspomnieć o upośledzonym wyrażeniu lambda. W Pythonie bowiem, wyrażenie lambda owszem istnieje, ale może się składać tylko z pojedynczego wyrażenia.<p>Nie to, żeby mi to jakoś szczególnie przeszkadzało, no ale szkoda…<h2>Komentarze</h2><p>Przejdźmy jednak do następnego punktu. Ponownie coś mało istotnego, co jest zresztą cechą wielu języków skryptowych. Otóż w Pythonie nie ma komentarzy blokowych. Jest to złe z co najmniej dwóch powodów.<p>Po pierwsze, nie ma łatwego sposobu (bez wykorzystania rozbudowanego edytora) na zakomentowanie dużego fragmentu kodu, szczególnie, że dodanie <code>if False:</code> na początku wymaga dokładnie takiej samej pracy (dodania wcięcia zamiast hasha).<p>Drugą wadą komentarzy liniowych (jeśli można je tak nazwać) jest fakt, że wszystko się psuje jeżeli wiersz zostanie zawinięty. I uwierzcie mi, zdarza się to nazbyt często na grupach czy w korespondencji mailowej.<p>Osobiście sądzę, iż Ritchie miał tutaj rację — sam komentarz blokowy w zupełności wystarcza, gdy tymczasem sam komentarz liniowy to zdecydowanie za mało.<h2>Magiczny przecinek</h2><p>Niemniej, moje ulubione dziwactwo, na które się natknąłem w składni Pythona to „magiczny przecinek” jak go zacząłem nazywać. Otóż poniższe dwie linijki są jak najbardziej poprawnym kodem Pythona i znaczą coś zupełnie innego:<pre>[ "a", "b" ]
[ "a" "b" ]</pre><p>Fajnie, nie? Żeby połączyć ze sobą dwa literały znakowe wystarczy napisać jeden obok drugiego bez żadnego operatora. Doprawdy boskie, a przynajmniej takie się wydaje do momenty gdy kilka razy o tym przecinku zapomnimy…<p>Krotki też dodają dodatkowej zabawy, no bo czy nie jest wyborne, że poniższa linijka jest jak najbardziej poprawnym kodem Pythona:<pre>"a",</pre><p>I bynajmniej, jej wynikiem nie jest ciąg znaków, a jednoelementowa krotka składająca się z ciągu znaków. Jakby nie można było w gramatyce zawrzeć, że krotki muszą być zawsze otoczone w nawiasy, o ile jaśniejsza byłby wówczas zapis i o ile trudniej o literówki.<p>(Zresztą idea tego typu danych też trochę mi umknęła, bo po co krotka skoro są tablice? Tak wiem, krotka nie może ulec zmianie, ale co z tego? No ale, Pythonem bawiłem się stosunkowo krótko, więc nie wnikam — wierzę, że jakiś powód na dodanie krotek był).<p>Na zakończenie o magicznym przecinku wspomnę jeszcze o magicznym princie. Print bowiem nie tylko oddziela argumenty spacją (przez co jeżeli chcesz wypisać dwie wartości bez odstępu musisz je jawnie skleić), ale dodaje na końcu znak przejścia do nowej linii. Co zrobić, jeżeli go nie chcemy? Magiczny przecinek przybywa na ratunek:<pre>print "hello,",
print "world"</pre><h2>do-while</h2><p>Czas odejść od spraw błahych i zająć się czymś poważniejszym. Zacznę od pętli do-while, a dokładniej jej braku.<p>W pierwszej chwili sądziłem, że to jakieś przeoczenie, że w tutorialu nie wspomnieli o do-while, ale nie… Python czegoś takiego zwyczajnie nie ma. Ciągle się zastanawiam jak można stworzyć język bez tak oczywistej konstrukcji. Jest to jedyny znany mi nieezoteryczny język imperatywny, w której takiej pętli nie ma.<p>W trakcie googlania spotkałem się ze stwierdzeniem, że każda przemyślana pętla może być zapisana w postaci pętli while — w tym momencie zacząłem się zastanawiać, czy gość, który to napisał, ma pojęcia o czym mówi, czy może uważa, że <code>while True: … if not warunek: break</code> to naprawdę ładna konstrukcja. Pocieszałem się tylko tym, że pewnie był to jakiś domorosły ekspert nie związany z tworzeniem Pythona.<h2>Widoczność pól klasy</h2><p>W 2004 roku wydany został PHP 5. Wspominam o tym dlatego, że jedną ze zmian w stosunku do PHP 4 było dodanie modyfikatorów zasięgu (<i>public</i>, <i>private</i> i <i>protected</i>). Tymczasem Python, mimo iż jest językiem starszym przez co wydawałoby się dojrzalszym, ciągle takich mechanizmów nie ma (przynajmniej w 2.6) i nadal opiera się na umowie „podkreślenie jest niepubliczne”.<h2>Dynamiczne typowanie i deklarowanie zmiennych</h2><p>I tak oto doszliśmy do najpoważniejszego moim zdaniem zarzutu. Winny jednak jestem słówko wyjaśnienia, bo niby co złego jest w dynamicznym typowaniu i braku deklaracji zmiennych? Przecież to upraszcza pisanie programów!<p>Rzeczywiście, upraszcza… pisanie stulinijkowych skryptów, ale gdy tylko zaczynamy pisać coś większe przeradza się w ogromną wadę. Wystarczy porównać te dwa skrypty, jeden napisany w Pythonie, a drugi w, tak przez wszystkich znienawidzonym, Perlu:<pre>import random
name = "Jane Doe"
if random.randint(0, 99) == 0:
print "Hello,", nmae
else:
print "Hi!"</pre><pre>use warnings;
use strict;
my $name = "Jane Doe";
if (rand(100) < 1) {
print "Hello, ", $nmae, "\n";
} else {
print "Hi!\n";
}</pre><p>Interpreter Pythona bez zmrużenia oka wykona podany skrypt i z 99% prawdopodobieństwem nie dowiemy się, że mamy literówkę. Tymczasem perl wyłoży się w momencie kompilacji (nawet bez <code>strict</code> dostaniemy ostrzeżenie).<p>Zupełnie analogiczny przykład można stworzyć na wadę dynamicznego typowania:<pre>import random
if random.randint(0, 99) == 0:
foo = "10"
else:
foo = 10
print foo + 10</pre><p>Tymi prostymi przykładami chcę pokazać, że dynamiczne typowanie i brak deklarowania zmiennych nie jest wcale czymś korzystnym. Efekt jest taki, że wiele błędów, które kompilator mógłby wykryć ujawniają się dopiero w czasie wykonania (a potem jest wielkie zdziwienie, gdy coś się wysypuje w trakcie prezentacji produktu na międzynarodowej konferencji).<p>Z tych powodów, miałem nadzieję, że w nowych językach, twórcy będą już od tego odchodzić i tak samo się stanie w Pythonie, ale niestety jego twórcy postanowili brnąć w tą ślepą uliczkę… Szkoda.<h2>Posłowie</h2><p>Gdy zaczynałem pisać projekt to do języka podchodziłem z entuzjazmem — wcięcia co prawda zawsze mnie odstraszały, ale tak go wszyscy zachwalali, że myślałem sobie, że może faktycznie jest taki wspaniały. Niestety zawiodłem się.<p>Pozostaje mi jedynie czekać na wydanie Perla 6.x86_64, wrażeniahttp://mina86.com/2008/07/18/x86-64-wrazenia2008-07-18T09:59:06Z2008-07-18T09:59:06ZMichał ‘mina86’ Nazarewiczhttps://mina86.com<p>64-bitowe procesory x86_64, x64, amd64, intel64, czy jak je tam chcemy zwać, zdobywają coraz większą popularność. Jest również coraz więcej systemów operacyjnych wykorzystujących ich potencjalne możliwości. Nareszcie pozbyliśmy się problemu przekręcenie licznika w 2038! Nareszcie możemy zaadresować 1 TiB fizycznej pamięci (to, że nasza płyta główna obsługuje 3 GiB, a jak mamy szczęście 3,5 GiB to już szczegół). Nareszcie mamy 48-bitową logiczną przestrzeń adresową (tj. 256 TiB)! Do tego dochodzi lepsza obsługa instrukcji SIMD, więcej rejestrów, 64-bitowa arytmetyka itp.<p>Rzecz jasna nie ma nic za darmo. Za te udogodnienia musimy płacić i bynajmniej nie chodzi mi o pieniądze, bo to raczej najmniej istotne — istotniejszą kwestią jest większe zużycie pamięci z powodu użycia ośmiobajtowych wskaźników, czy wyrównania stosu do ośmiu bajtów nawet jeżeli zrzucamy na niego liczbę 32-bitową. Do tego dochodzi jeszcze bardziej skomplikowany, a przez to wolniejszy, proces tłumaczenia adresów logicznych na adresy fizyczne.<p>Jaki jest rezultat? Z zainstalowanym Slackwarem na moim komputerze z 512 MiB pamięci mogłem mieć uruchomione dziesiątki programów w tym Gimpa z otworzonym jakimś niemałym obrazkiem, a system i tak radził sobie bez swapu. Gdy zainstalowałem Slamd64 <span lang=en>OOM killer</span> co i rusz zabijał mi jakiś proces. Po kilku dniach zdecydowałem się wrócić do poprzedniego stanu rzeczy.<p>Jaki z tego morał? Jeżeli jesteś zwykłym użytkownikiem nie baw się w 64-bitowe systemy o ile nie masz dużo RAM-u, bo nie będziesz miał z tego większych korzyści, a co więcej możesz zauważyć negatywne skutki. Zresztą nawet jeżeli masz dużo pamięci przechodzenie może okazać się zbytnim zachodem jeżeli korzystasz już z systemu 32-bitowego. Do roku 2038 mamy jeszcze 30 lat, pamięć do 64 GiB można obsłuży dzięki <a href=//en.wikipedia.org/wiki/Physical_Address_Extension>PAE</a>, 48-bitowej przestrzeni adresowej nie potrzebuje żaden z programów, które używasz, z SSE3 gcc pewnie i tak nie umie skorzystać, 64-bitowa arytmetyka jest wykorzystywana przez zaledwie kilka programów, które i tak nie są krytyczne dla szybkości systemu (zob. <a href=//pl.wikipedia.org/wiki/Prawo_Amdahla>prawo Amdahla</a>), a korzyści wynikające z większej liczby rejestrów mogą zniknąć w cieniu większego zużycia pamięci.<p>Nie twierdzę, że 64-bitowy procesor jest złym wyborem, ale w wielu sytuacjach (mówię głównie o zastosowaniach „domowych”) nie ma co liczyć, że jak za sprawą dotknięcia czarodziejską różdżką nasz komputer zacznie działać szybciej, gdy przejdziemy na 64-bitowy system, w sytuacji, gdy mamy stosunkowo mało RAM-u.Wrażenia z Gentoohttp://mina86.com/2008/02/12/wrazenia-z-gentoo2008-02-12T05:19:04Z2008-02-12T05:19:04ZMichał ‘mina86’ Nazarewiczhttps://mina86.com<p id=prologue>Ostatnio, przy okazji zmiany systemu plików z Reiser4 na <a href=//en.wikipedia.org/wiki/Ext3>ext3</a> postanowiłem zainstalować <a href=//www.gentoo.org/ >Gentoo</a>. Głównym motywem był jednak nie system plików, a fakt posiadania 64 bitowego procesora, który nie jest wspierany przez <a href=http://www.slackware.org/ >Slackware</a> - dystrybucję, którą używam. Tak, wiem o istnieniu <a href=http://www.slamd64.com/ >Slamd64</a>, ale od tej dystrybucji wolę trzymać się z daleka… (Update: Na chwilę obecną, gdy dodaję ten wpis do Joggera, mogę powiedzieć, że Slamd64 12.0 nie jest wcale takie złe i działa całkiem stabilnie i przyjemnie.)<p>Poniższego artykułu nie należy traktować jako opisu rzetelnych badań, ale jako moją prywatną opinię na temat Gentoo oraz różnych aspektów z nim związanych.<p>Chciałbym również zaznaczyć, że początkowo nie byłem do Gentoo nastawiony negatywnie. Owszem, żałowałem trochę, że odchodzę od Slackware’a, ale mimo wszystko cieszyłem się z myśli, że w końcu wykorzystam pełen potencjał swojej 64 bitowej maszyny.<h2 id=compilation>Kompilacja</h2><p>Gentoo jest najbardziej znane z tego, że mało jest tam tzw. <i>paczek</i> i wszystko należy kompilować ręcznie. Pojawia się pytanie po co? W <a href=http://openbsd.chem.uw.edu.pl/faq/pl/index.html>FAQ-u OpenBSD</a> <a href=http://openbsd.chem.uw.edu.pl/faq/pl/faq5.html#WhySrc>wyczytać można</a> co następuje:<blockquote><p>Dlaczego potrzebuję systemu zbudowanego ze źródeł?<p>Właściwie, jest bardzo prawdopodobne że nie potrzebujesz.<p>Kilka powodów dlaczego NIE budować ze źródeł: […]<ul><li><strong>Nie</strong> uzyskasz lepszej wydajności systemu poprzez zbudowanie go ze źródeł.<li>Zmiany opcji kompilatora mogą bardziej zepsuć twój system niż go udoskonalić.</ul></blockquote><p>Można się zastanawiać czy stwierdzenia powyższe dotyczą jedynie <a href=http://www.openbsd.org/ >OpenBSD</a> czy też przenoszą się do świata GNU/Linuksa. Z pobieżnych testów dozziego wynika, że istotnie — flagi kompilatora nieznacznie wpływają na szybkość działania aplikacji toteż aplikacja skompilowana dla procesora i486 z optymalizacją dla i686 będzie działać praktycznie tak samo szybko jak ta sama aplikacja skompilowana dla procesora i686.<p>Pozostaje jednak konfiguracja samego programu przed skompilowaniem (np. przy użyciu <code>./configure</code>). Sytuacja tutaj wygląda w zasadzie podobnie. Poza tym, w Gentoo zmiana tych opcji odbywa się poprzez zmienną <code>USE</code> tak, że <code>emerge</code> samo automatycznie wszystko ustawia i kompiluje potrzebne pakiety. Oznacza to, że prędzej czy później jakaś paczka, która została skompilowana z minimalną liczbą opcji, np. bez obsługi <a href=http://www.postgres.org/ >PostgreSQL</a>-a, nagle zostanie przekompilowana z jego obsługą, bo chcieliśmy, żeby jakaś inna aplikacja tą bazę danych obsługiwała więc dodaliśmy odpowiedni wpis do <code>USE</code>.<p>Oczywiście można edytować <i>ebuild</i>y, ale w takim razie po co ten cały <code>emerge</code> i <code>portage</code>, skoro i tak będzie trzeba ręcznie konfigurować programy? W tym momencie czym to się różni od ściągnięcia źródeł paczki Slackware’a i edycji <i>SlackBuild</i>a? Moim zdaniem niczym.<p>Mogę jeszcze dodać, że w moim przypadku Gentoo, w którym wszystko było kompilowane z odpowiednimi flagami i jako aplikacje 64 bitowe działał zauważalnie wolniej niż Slackware, w którym część paczek była dla i486, a część i686.<h2 id=auto>Automatyka i zależności</h2><p>Nie mam nic przeciwko automatyce. Napisałem nawet sporo małych skryptów, które pomagają mi wykonywać różne małe czynności jak i większe takie jak <code>installkernel</code> (wchodzący w skład <a href=http://tinyapps.sourceforge.net>TinyApps</a>) pozwalający na całkowite zautomatyzowanie procesu kompilacji i instalacji kernela. Jednakże, automaty mają robić to co chce od nich użytkownik, a nie to co one myślą, że chce użytkownik. Dlatego właśnie nie lubię zależności. Systemy z zależnościami myślą, że wiedzą lepiej co mają zainstalować, gdy tymczasem użytkownik mógł w międzyczasie zainstalować coś ręcznie. Jak tak zrobiłem np. z kernelem i jego źródłami. Ostatecznie coś tam wyczarowałem co teoretycznie miało spowodować, że <code>emerge</code> miał myśleć, że paczka ze źródłami kernela jest zainstalowana, ale jakoś niezbyt chciało to działać.<p>Rzecz jasna można robić <i>ebuild</i>a, ale skoro wszystko robi się automatycznie to dlaczego mam tam grzebać? ;) O wiele bardziej odpowiada mi sytuacja, gdy nie ma zależności. W Slacku działa to całkiem dobrze - jeżeli zainstaluje się jakąś paczkę i brakować jej będzie zależności to przy uruchomieniu aplikacji widać komunikat błędu z informacją, że brakuje jakiejś biblioteki. Wystarczy doinstalować paczkę, w której się ona znajduje i po sprawie.<p>Wiele osób zarzuca systemom bez zależności, że skompilowanie czegoś lub dodanie jakiejś paczki jest mordęgą, bo trzeba ręcznie polować na setki zależności. Zupełnie nie wiem o co takim ludziom chodzi! Często kompiluje sobie różne programy (które zazwyczaj szybko wywalam) i rzadko mi się zdarza, żebym musiał doinstalowywać jakieś biblioteki - zazwyczaj wszystko jest. A aplikacje, które wymagały więcej niż jednej biblioteki, można zliczyć na palcach jednej ręki.<p>Należy również pamiętać, że system zależności z błędami jest znacznie gorszy (pod każdym względem) od systemu bez zależności. Co jeżeli ktoś źle wpisze jakie pakiety są wymagane przez paczkowaną przez siebie aplikację? W końcu jeżeli w repozytorium jest kilka tysięcy programów i bibliotek to wcale nie trudno o pomyłkę. Konsekwencje takiego błędu mogą być często opłakane a już na pewno irytujące.<h2 id=enough>Miarka się przebrała</h2><p>W zasadzie na początku Gentoo całkiem mi się podobał. Wielu krzyczało, że instalacja tego to koszmar, ale jakoś tego tak nie odczułem. Szkoda tylko, że <code>portage</code> (czy tam <code>emerge</code>) zaczął w pewnym momencie ściągać wszystko z Internetu, gdy tymczasem przede mną leżała płytka z wypalonymi pakietami binarnymi i czymś tam jeszcze - niby nic, ale dla kogoś o niezbyt szybkim łączu to spora strata czasu.<p>Byłem w stanie wybaczyć temu systemowi, że bezsensownie (moim zdaniem) ściąga źródła wszystkiego z Internetu i traci czas na kompilacje, ale miarka się przebrała, gdy postanowiłem wszystko uaktualnić. Niby wszystko jest najnowsze, ale jako, że gość sam mi wszystko instalował to ostatecznie nie do końca wiedziałem co mam na dysku, a przecież wydanie komendy do aktualizacji wszystkich pakietów na pewno nie zaszkodzi.<p>Tak właśnie myślałem. I grubo się myliłem.<p>Po jakimś czasie <code>emerge</code> przerwał pracę z jakimś błędem. Nie byłem w stanie uruchomić żadnego programu - w większości próby odpalenia czegokolwiek kończyły się wdzięcznym <i lang=en>command not found</i>. W takim razie zrestartowałem komputer i wówczas odkryłem co się stało - <code>emerge</code> wywalił całe <code>coreutils</code> (czy jak ta paczka się nazywa na Gentoo) lub jakąś podobną, krytyczna do działania systemu paczkę co skutecznie uniemożliwiło mi dalsze z niego korzystanie. Od tego momentu Gentoo jest niemile widziany na moim dysku.<h2 id=epilogue>Epilog</h2><p>Niektórzy twierdzą, że Gentoo jest dla osób, które chcą wszystko dopieścić w swoim systemie, ale sorry… Moim zdaniem nie opłaca się kompilować jakiejś aplikacji przez dzień czy dwa, żeby uruchamiała się o milisekundę krócej. Największy problem polega na tym, że kompilacja ma sens tam gdzie stawianie Gentoo trwałoby miesiące, czyli na wolnych komputerach, bo właśnie tam różnice prędkości są najbardziej zauważalne.<p>Nie twierdze, że ręczna kompilacja to coś złego. Sam kompiluje niektóre aplikacje pomimo, że są one dostępne spaczkowane dla Slackware’a. Zauważam jedynie, że gdzieś trzeba postawić granicę i Gentoo moim zdaniem tą granicę przekroczył. Wiele osób mówi o mnie, że jestem maniakiem, bo potrafię siedzieć godzinami i konfigurować jakiś program (<a href=http://www.fvwm.org/ >FVWM</a>-a konfigurowałem kilka dni), ale okazuje się, że blado wypadam na tle użytkowników Gentoo (bez obrazy dla kogokolwiek), którzy potrafią godzinami kompilować przeróżne aplikacje.