Doczekaliśmy się. Po kilkunastu (!) latach od wydania pierwszej części, Starcraft 2 ujrzał dzisiaj światło dzienne (w Europie). Sam oczekiwałem na tę premierę bardzo długo, mimo że nie jestem jakimś wielkim fanem oryginału, a moje umiejętności kierowania którąkolwiek z trzech ras są raczej skromne :) Od dawna tęskniłem jednak za grą niewymagającą dużą czasu, a jednocześnie nie będą jakimś – tfu, tfu – casualem. RTS-y świetnie w tej roli spisują.
Oczywiście nie znaczy to, że rzucę SC2 w kąt po rozegraniu trzech misji ;P O nie, nie ma mowy. Już teraz mogę bowiem stwierdzić, że mimo podążania za kilkoma nieco denerwującymi trendami w obecnym przemyśle gier (czyli wszechobecnymi achievementami, koniecznością rejestracji online i całymi tymi niby-facebookowymi bajerami), Starcaft 2: Wings of Liberty jest bardzo udaną kontynuacją jedynki.
Tak więc narodowy sport Korei Południowej doczekał się sequela, natomiast blog przynajmniej w tym miesiącu nowej notki na pewno się nie doczeka ;P
Wczoraj naciąłem się na nieprzyjemny rodzaj błędu w kodzie. Opierając się na powiedzeniu “Najciemniej pod latarnią”, można by go określić jako nieprzenikniona ciemność tuż pod najjaśniejszą latarnią w całym mieście. Normalnie nikomu nie przyjdzie do głowy, by jej tam szukać. Chodzi bowiem o jakąś “oczywistość”, w którą wątpienie jest nie tyle nierozsądnie, co wręcz nie przychodzi nawet na myśl.
A wszystko dlatego, że lubię prostotę – przynajmniej w takich kwestiach, jak wyniki funkcji informujące o ewentualnych błędach. Prawie zawsze są to u mnie zwykłe bool
e, informujące jedynie o tym, czy dana operacja się powiodła lub nie. To wystarcza, bo do bardziej zaawansowanego debugowania są logi, wyjątki, asercje i inne dobrodziejstwo inwentarza. A same wywołania funkcji możemy sobie bez przeszkód umieszczać w if
ach czy warunkach pętli.
Są jednak biblioteki, które “twierdzą”, że taka konwencja jest niedobra i proponują inne. Pół biedy, gdy chodzi tu o coś w rodzaju typu HRESULT
, do którego w pakiecie dostarczane są makra SUCCEEDED
i FAILED
. Zupełnie nie rozumiem jednak, co jest pociągającego w pisaniu np.:
Usprawiedliwiać się mogę jednak tym, że… no cóż, to przecież Linux ;-) Ale kiedy dostaję do ręki porządną bibliotekę z klasami, wsparciem dla STL-a i CamelCase w nazwach funkcji, to przecież mogę się spodziewać czegoś rozsądniejszego, prawda? Skąd może mi przyjść do głowy, że rezultat zero ma oznaczać powodzenie wykonania funkcji?!
Najwyraźniej jednak powinienem taką możliwość dopuszczać. Okazuje się bowiem, że nawet dobrze zaprojektowane, estetyczne API może mieć takie kwiatki. Przekonałem się o tym, próbując pobrać wartość atrybutu elementu XML, używając biblioteki TinyXML i jej metody o nazwie QueryStringAttribute
. W przypadku powodzenia zwraca ona stałą TIXML_SUCCESS
; szkoda tylko, że jej wartością jest… zero ;P
Więc zaprawdę powiadam wam: nie ufajcie żadnej funkcji, której typem zwracanym nie jest bool
!
Wymowa słów w lojbanie.
Moje trwające już kilka miesięcy zainteresowanie lojbanem pewnie nie przetrwałoby tak długo, gdyby był on czymś w typie esperanto – a tym, jak wiemy, na pewno nie jest. Przeglądanie jego “formalnej definicji” (czyli The Lojban Reference Grammar) sprawia raczej wrażenie czytania dokumentacji języka programowania, biblioteki lub innego API. Jest to więc całkiem przyjemna lektura :)
Nie zapominajmy jednak, że lojban jest mimo wszystko pomyślany jako język (również) dla ludzi, i to także do – szok! horror! – mówienia. Posiada więc również określone reguły wymowy wyrazów. Są one zresztą określone bardzo dobrze, gdyż niewielki poziom ich skomplikowania nijak ma się do złożonych i nie zawsze jasnych niuansów wymowy języków naturalnych. Można to łatwo zauważyć, kiedy przyjrzymy się im z bliska.
Rozszerzalność od dawna jest w modzie: praktycznie żadna poważniejsza aplikacja nie obywa się bez jakiegoś systemu pluginów, czyli “wtyczek” zwiększających jej funkcjonalność. Niektóre robią to przy okazji (acz ze słusznych powodów), inne czynią z elastyczności i rozszerzalności swój główny oręż (patrz np. uniwersalne komunikatory w typie Mirandy). Wszystko to kojarzy się trochę linuksiarsko, jednakże obecnie także wiele programów stricte pod Windows zachęca (a przynajmniej umożliwia) swoich użytkownika do zakasania rękawów i zakodowania im nowych funkcji.
Dotyczy to także aplikacji na platformę .NET. Co więcej, sama jej natura ułatwia budowanie programów wspierających koncepcję rozszerzalności. Rzecz opiera się na pojęciu assembly, czyli czegoś w rodzaju pakietu (javowe skojarzenia wskazane) zawierającego kod, a więc klasy. Ze względu na to, że .NET Framework zawiera wbudowany kompilator, jest zupełnie możliwe, by nasz program udostępniał całe środowisko do pisania do niego pluginów, a następnie przerabiania ich na kod wykonywalny i podłączania ich do aplikacji. Nie twierdzę, że znam program, który rzeczywiście tak robi, ale przynajmniej w teorii jest to możliwe :)
Powszechniejsze wydaje mi się prostsze podejście, w którym assembly dostarcza się w postaci skompilowanej. Zazwyczaj jest to biblioteka .NET-owych, zapisana jako plik .dll, niemający przy tym zbyt wiele wspólnego z natywnymi czy COM-owymi DLL-ami. Wczytanie go jest bardzo proste, gdy wykorzystujemy do tego klasę System.Reflection.Assembly
:
Wskazana jest tutaj ostrożność np. w postaci zapewnienia, że każde assembly ładujemy tylko raz. Najlepiej jest wyznaczyć osobny podkatalog na wtyczki do naszego programu i ładować je jednokrotnie, zapewne podczas uruchamiania samej aplikacji.
Gdy mamy już gotowy obiekt klasy Assembly
(niezależnie od tego, czy skompilowaliśmy go sami czy wczytaliśmy go z gotowej binarki tak, jak powyżej), chcielibyśmy pewnie jakoś wykorzystać zawarty w nim kod. Są nim oczywiście jakieś klasy, które możemy pobrać metodą GetExportedTypes
. Zwróci nam ona metody tablicę obiektów Type
, czyli znanej zapewne metaklasy należącej do .NET-owego systemu refleksji. Z nimi zaś zrobić możemy… no, prawie wszystko :) Do interesujących w kontekście pluginów czynności należy przede wszystkim sprawdzenie, czy dana klasa implementuje jakiś ustalony przez nas interfejs “wtyczkowy”, a następnie utworzenie jej obiektu:
Takie beztroskie, dynamiczne tworzenie obiektów z binarnego kodu wczytanego już w trakcie działania programu jest jak najbardziej możliwe i, jak widać wyżej, całkiem proste – stosujemy do tego metodę CreateInstance
klasy o wdzięcznej nazwie Activator
. Wymogiem jest obecność w klasie wtyczki odpowiedniego konstruktora. W powyższym kodzie zakładamy na przykład najprostszy przypadek, iż dostępna jest jego wersja bezparametrowa.
To w sumie wszystko, jeśli chodzi o wczytywanie. To, w jaki sposób plugin może rozszerzać możliwości naszej aplikacji, zależy głównie od zawartości interfejsu, który nazwałem tutaj umownie IPlugin
. Projektując go, powinno się zadbać o jego elastyczność i prostotę, a także wziąć pod uwagę chociażby kwestie bezpieczeństwa.
Obecne temperatury są uciążliwe nie tylko dla nas – organizmów opartych o białka i węgiel, ale też dla naszych półprzewodnikowych, krzemowych gadżetów. Dotyczy to również komputerów oraz ich procesorów. Jak każde układy scalone, mają one tendencję do nagrzewania się – czasem nadmiernego. Dlatego dobrze jest monitorować temperaturę procesora.
Istnieje oczywiście wiele gotowych aplikacji, które na to pozwalają, ale przecież zawsze fajniej jest zakodować coś samemu, nieprawdaż? :) A już zupełnie świetnie jest wtedy, gdy użyjemy do tego naszego ulubionego narzędzia do administrowania systemem, czyli PowerShella.
Przy jego pomocy pobranie aktualnej temperatury procesora nie jest trudne. Posługujemy się do tego WMI – Windows Management Instrumentation – które to jest rozszerzeniem modelu sterowników systemu Windows, pozwalającym m.in. na monitorowanie różnego rodzaju informacji diagnostycznych. PowerShell zawiera wbudowane komendy, pozwalające na tworzenie obiektów WMI – wśród nich również takich, które udostępniają informacje na temat temperatury procesora:
Z bliżej nieokreślonych powodów wartość temperatury podawana jest w dziesiątych częściach kelwinów, więc konieczne jest ich przeliczenie na stopnie Celsjusza. Ponadto istnieje też prawdopodobieństwo, że używana tutaj klasa WMI o nazwie MSAcpi_ThermalZoneTemperature
nie jest dostępna na naszym komputerze – zależy to prawdopodobnie od modelu jego płyty głównej. W moim przypadku powyższy kod działał bez problemu na komputerze stacjonarnym, lecz nie na laptopie. Może to i dobrze… Mam bowiem uzasadnione przeczucie, że temperatura tamtejszego procesora wcale by mi się nie spodobała ;)
Panuje obecnie moda na to, aby strony WWW jak najskuteczniejszej udawały, że nimi nie są i zamiast tego mieniły się ‘aplikacjami internetowymi’. Duża w tym zasługa możliwości JavaScriptu w nowoczesnych przeglądarkach. Jeśli potrafimy przeboleć pisanie w nim, to możemy osiągnąć całkiem efektowne rezultaty. Albo takie nieco mniej imponujące, ale też zgrabne :)
Do tej drugiej kategorii należy efekt znany jako watermark textbox, niemający wbrew pozorom żadnego związku ze znakami wodnymi w obrazkach. Trik ten – z którym zapewne tutejsza większość się zetknęła – polega na wyświetlaniu nieco przyszarzonego komunikatu w polu tekstowym, który następnie znika, gdy użytkownik umieści w nim kursor. Oprócz sprawiania wrażenia, że “strona żyje”, ta prosta sztuczka ma też wymiar praktyczny: pozwala oszczędzić na zbędnej etykiecie textboxa.
Chcąc “wodne” pole tekstowe umieścić na swojej stronie, możemy skorzystać z jednego z gotowych rozwiązań. Wiele z nich używa jQuery – darmowej biblioteki ułatwiającej pisanie w JS. Jeśli jednak nie korzystamy z niej w innych miejscach strony, to wymaganie jej obecności nie musi się nam podobać. A ponieważ watermark textbox jest efektem łatwym do zakodowania, spokojnie możemy napisać go własnoręcznie. Prześledźmy zatem, jak da się to zrobić.
Jednym z powodów, dla których nie lubię diagramów blokowych, jest ich prymitywna notacja przedstawiania instrukcji sterujących. Jedyne, czym się tam dysponuje, to if
i skok. Jak przy pomocy tylko tego można w klarowny sposób przedstawić jakikolwiek nietrywialny algorytm? To trochę tak, jakby w programowaniu używać tylko pętli nieskończonych i instrukcji break
.
Można to robić, oczywiście, ale konsekwencje nie są zbyt ciekawe. Jeśli kryterium opuszczenia pętli jest tak skomplikowane, że trzeba je rozbić na kilka konstrukcji if
–break
i żadna z nich “nie zasługuje” na wyciągnięcie do warunku w samym while
/for
, to coś tu brzydko pachnie. Nie chciałbym być w skórze tego, kto będzie musiał później takie dzieło debugować.
W bardziej rozsądnych przypadkach da się uniknąć pętli nieskończonych, nawet jeśli od razu nie widać, jak można by to zrobić. I tak odkryłem na przykład, jak można to ładnie zrobić w sytuacji podobnej do poniższej:
Nazywam to pętlą z wyróżnionym startem, bo typowa jej postać, która nie zawiera (pozornie) nieskończonego kręcenia się w kółko, wygląda tak:
Cała zabawa polega na tym, że pierwsze wywołanie SomeFunction
może dać niepoprawną wartość w foo
. (Może to być jakieś wyszukiwanie w pojemniku i element odpowiadający kluczowy sth
nie został w ogóle znaleziony). Sama treść pętli nie może być wtedy wykonana, bo zdarzy się zapewne jakieś nieszczęście. Dlatego trzeba wyodrębnić to pierwsze wywołanie, i oczywiście zadbać także o kolejne. A to daje, jak widać, dublowanie kodu. Chciałoby się to zrobić lepiej.
I można, na szczęście. Możemy za to podziękować feature‘owi C++, który często bywa krytykowany jako ułatwiający popełnianie błędów. Bowiem to dzięki temu, że instrukcja przypisania zwraca wartość przypisywaną, możemy to wszystko zapisać tak:
Zdaję sobie sprawę, że dla wielu fakt ten jest równie oczywisty jak pisanie return a == b;
zamiast:
ale dla niektórych taka postać pętli for
może być zupełnie zaskakująca. Pamiętajmy, że kiedyś (prawie) każdy pisał też i takie if
y jak powyżej ;-)