W C++ istnieje słowo kluczowe using
, z którym zetknął się chyba każdy. Zwykle dotyczy to nieśmiertelnej linijki:
Dlatego też słowo to kojarzy się przede wszystkim z przestrzeniami nazw (namespaces), a najczęściej tylko i wyłącznie z nimi.
Jednak using
ma też swoje zastosowanie – i to zapewne znacznie ciekawsze – przy definiowaniu klas. Formalnie rzecz ujmując, słówko to pozwala wprowadzić składową pochodzącą z klasy bazowej (metodę lub pole) do zasięgu klasy pochodnej. Niezbyt to ekscytujące na pierwszy rzut oka, ale faktem jest, że dzięki skorzystaniu z using
możemy dokonać przynajmniej jednej koniecznej czasami operacji. Możliwa jest mianowicie zmiana kontroli dostępu do danego składnika klasy, czyli określenie, czy ma on być prywatny czy może publiczny.
Wyobraźmy sobie na przykład, że w klasie bazowej mamy jakieś funkcje niepubliczne, które chcemy udostępnić na zewnątrz w klasie pochodnej:
Sytuacja nie jest wcale taka hipotetyczna. Sam miałem ostatnio taki przypadek, gdy najwygodniej było po prostu wbudować w klasę bazową pewną ukrytą funkcjonalność, która była używana przez wiele z jej klas pochodnych do ich wewnętrznych celów. Jednak niektóre z tych klas musiały tę “bazową” funkcjonalność udostępnić na zewnątrz jako publiczną. I tu przydało się użycie using
w sposób zaprezentowany wyżej. (Dla zainteresowanych wspomnę, że opisywana sytuacja praktycznie wystąpiła u mnie w kodzie systemu GUI :]).
Gdy zawzięcie i wytrwale tworzymy jakiś koderski projekt, chciałoby się od czasu do czasu zmierzyć, ile to już pracy zdołaliśmy w nim wykonać. Pewnym sposobem na to jest policzenie ilości wszystkich linii kodu, które udało nam się już napisać.
Istnieją do tego nawet oddzielne aplikacje, niekiedy z rozbudowanym interfejsem graficznym. Jednak takie proste zadanie można by przecież zrealizować przy pomocy równie prostego narzędzia. Jakiego? Oczywiście – niewielkiego skryptu PowerShella :) Chociażby takiego jak ten:
Podajemy mu tylko ścieżkę do katalogu z naszym kodem, a on przeglądnie wszystkie pliki z ustalonymi rozszerzeniami i wyświetli statystykę z liczbą linii: wszystkich oraz niepustych. Cała ta czynność ta nie zajmuje w kodzie specjalnie dużo miejsca, gdyż najważniejsze jej elementy: pobranie podkatalogów, plików w katalogu i wierszy tekstu w pliku dają się zrobić pojedynczymi wywołaniami funkcji (odpowiednio: GetDirectories
i GetFiles
z System.IO.Directory
oraz System.IO.File.ReadAllLines
). To aczkolwiek zasługa nie samego PowerShella, tylko niezawodnej platformy .NET ;)
Skrypt ten można rzecz jasna znacznie usprawnić, pozwalając chociażby na definiowanie filtra nazw plików z kodem w jego wywołaniu czy też umożliwiając wykluczanie niektórych katalogów (np. bin, Debug, Release) w celu przyspieszenia zliczania. Jeśli ktoś miałby na to ochotę, może się dodawaniem takich feature‘ów pobawić :)
Dawno, dawno temu… A właściwie to prawie dokładnie rok temu z bliżej niewyjaśnionych do dzisiaj przyczyn naszła mnie ochota, aby reaktywować swoją stronę domową w postaci tego oto (dev)bloga. Od tego czasu zdążyło zmienić się sporo, ale wbrew przeciwnościom losu (uosabianym głównie przez lenistwo, które to, jak wiadomo, ma wśród wszystkich zadań zawsze najwyższy priorytet :]) blog ów nadal istnieje i nie wydaje się, żeby przynajmniej w najbliższej przyszłości miało się coś w tej kwestii zmienić. Bowiem podobno rok właśnie to taka magiczna granica, której przekroczenie udaje się tylko w mniej więcej połowie przypadków. Oczywiście to tylko statystyka (a według niej ja i mój pies mamy po trzy nogi), ale daje ona chociaż powody do umiarkowanego optymizmu – a ich nigdy dosyć.
Ten rok był też czasem “ucierania się” stylu oraz tematyki tego, co w regularnych odstępach czasu staram się tutaj publikować. Po drodze życie zweryfikowało rzecz jasna zbyt ambitne założenia i z devloga zrobiło się… no właśnie, powiedzmy, że ‘blog IT’ – żeby nie powiedzieć “nie-wiadomo-co” :) W zasadzie nie było to zresztą trudne do przewidzenia: aby systematycznie zdawać relacje z koderskiej pracy w sposób chociaż śladowo interesujący, trzeba by chyba dysponować dobą o długości co najmniej 50 godzin. Nie da się też ukryć, że formuła devloga jest też dość sztywna i zapewne dla niewielu czytelników byłaby ona na swój sposób ciekawa.
Z tych (i pewnie nie tylko z tych) powodów założona forma ewoluowała w kierunku czegoś nieco odmiennego, albo raczej trochę rozszerzonego względem pierwotnych planów. Zamiast opisywać tylko to, co ostatnio udało mi się zakodować, zacząłem też włączać różnego rodzaju programistyczne ciekawostki, dziwnostki, sugestie, porównania, krótkie omówienia, wskazówki, przemyślenia i inne tego typu “kawałki informacji”, opatrzone zwykle moją subiektywną opinią lub komentarzem. Trudno powiedzieć, co tak naprawdę je łączy – naturalnie poza technikaliami w rodzaju często przewijających się języków lub platform programistycznych. Publikując je spodziewam się jednak, że ktoś może na nie przypadkiem lub celowo natrafić i stwierdzić: “O, to całkiem interesujące…” albo “Hej, tego wcześniej nie wiedziałem!”. Być może w ten sposób zainteresuje się też jakimś tematem i zapragnie rozszerzyć swoją wiedzę w danym kierunku, co rzecz jasna przyniesie pożytek nie tylko jemu (lub jej).
Wychodzi więc na to, że mamy do czynienia z wysoce subiektywnym, nieuporządkowanym, a także stronniczym, wybiórczym i w gruncie rzeczy nie do końca godnym zaufania źródłem informacji na tematy okołokoderskie i okołoinformatyczne. Cóż to więc za dziwny twór?… Zapewne z braku lepszych określeń pozostaje posługiwanie się bardzo ogólnym słowem-wytrychem: blog.
Muszę tutaj zaznaczyć, że przyznanie się do prowadzenia czegoś, co tak właśnie można nazwać, to dla mnie coś wciąż jeszcze lekko kłopotliwego. Dlaczego? Ano dlatego, że termin ‘blog’ nadal kojarzy mi się trochę ze złotą erą różowiasto-pokemoniastych wynurzeń znudzonych dwunastolatek :) Wiem, wiem – teraz to już przeszłość lub margines, a blogowanie stało się sprawą poważną, powszechną i różnorodną. Przepastna blogosfera (paskudny neologizm, swoją drogą) powinna zatem bez problemu pomieścić także i to, czym w regularnych odstępach czasu raczę wszystkich, którzy pojawiają się na tej stronie.
A zatem minął pierwszy rok istnienia tego bloga, zaś jednocześnie liczba zamieszczonych na nim notek wraz z niniejszą osiągnęła dokładnie 256 – co jest przecież porządną i bardzo okrągłą liczbą :) Zbieżności obu tych zdarzeń komentować raczej nie będę (;P), a zamiast tego pozwolę sobie wyrazić nieśmiałe życzenie – od siebie dla siebie i wszystkich czytających – abyśmy doczekali się kolejnych rocznic i jeszcze co najmniej kilku podobnych okazji. Ze swej strony mogę zapewnić, że dołożę wszelkich możliwych starań, aby tak właśnie się stało.
Bez używania mechanizmu odśmiecania istnieje zawsze ryzyko, że skończymy z odwołaniem do obiektu, który został już zniszczony. (Przy używaniu GC też istnieje taka możliwość, ale musielibyśmy niejako sami się postarać, aby wystąpiła). Dlatego zaleca się na przykład, by każdemu wywołaniu delete
towarzyszyło zerowanie wskaźnika:
dzięki czemu można ochronić się przez problemem wiszących wskaźników (dangling pointers).
Można? No cóż, nie do końca. Istnieje jeszcze możliwość, że obiekt zniszczy się sam, używając po prostu instrukcji delete this
(jest to jak najbardziej legalne). A wtedy wszelkie odnoszące się do niego odwołania będą już nieważne.
Chyba że… obiekt sam je wyzeruje. Istnieje mianowicie śmieszny trik, polegający na przekazaniu do niego w konstruktorze wskaźnika na siebie (self-pointer):
A mówiąc dokładniej: wskaźnika na ów wskaźnik (zaczyna się robić ciekawie, prawda? ;]). Musi być on oczywiście zapamiętany, a cała sztuczka polega na tym, że w destruktorze obiektu następuje jego zerowanie:
I teraz obiekt może radośnie się usuwać kiedy tylko zechce. A tak swoją drogą, jeśli rzeczywiście może on zniknąć w każdej chwili, to może wypadałoby też, aby sprawdzał, czy przypadkiem… już nie istnieje:
Pokręcone i przekombinowane? Powiedziałbym wręcz, że szalone :) Ale do takich sztuczek trzeba się uciekać, jeśli nie korzystamy z mechanizmów odśmiecania pamięci i nie potrafimy jednoznacznie określić czasu życia obiektów i ich wzajemnej przynależności.
Albo po prostu: gdy nie mamy lepszych pomysłów. Bo przecież w ostateczności lepiej chyba sprawdzi się zwyczajna flaga logiczna z metodą typu IsAlive
, jeśli obiekt rzeczywiście może popełnić nagłe samobójstwo. Najlepiej jednak, żeby takich emo-obiektów było jak najmniej ;)
Kiedy w C++ chcemy przekazać do funkcji odwołanie do obiektu (zezwalające na jego modyfikację wewnątrz funkcji), mamy do wyboru dwie metody. Ta alternatywa to posłużenie się wskaźnikiem albo referencją:
Czy istnieje uniwersalna odpowiedź na to, którą wybrać? Chyba nie. Jeśli chodzi o wskaźnik, to za jego użyciem może przemawiać:
NULL
jako domyślnej wartości dla tego parametru w deklaracji funkcji. Nie jest to możliwe dla referencji (w C++).&
, który daje o tym jakąś widoczną wskazówkę (nie tak jasną jak ref
/out
w C#, ale zawsze). Nie jestem też wielkim fanem notacji węgierskiej, lecz w przypadku wskaźników stosowanie przedrostka p
wydaje mi się akurat wskazane i w tym kontekście też zwiększa czytelność wywołania funkcji, wskazując, że przekazywany obiekt (alokowany na stercie) też może się zmienić.
Z kolei referencje mogą się popisać innymi zaletami:
(*pArray)[i]
, zaś przez referencję po prostu jako array[i]
.Widać więc, że jeśli kwestia odwołania pustego nie jest dla nas istotna, to decyzja może być trudna. Ale naturalnie jest tak tylko wtedy, gdy zechcemy się nad takimi sprawami zastanawiać ;]
W dzisiejszych czasach niemal każdy edytor plików tekstowych nieco bardziej zaawansowany od windowsowego Notatnika oferuje funkcję kolorowania składni (syntax highlighting) przynajmniej kilku najpopularniejszych języków programowania. W przypadku całych IDE jest to oczywiście funkcjonalność absolutnie oczywista i niezbędna, jednak coraz więcej środowisk oferuje też coś więcej. Coś, co dla odróżnienia nazywam kolorowaniem semantycznym; nie jestem bowiem pewien, czy ten mechanizm ma jakąś ogólnie przyjętą nazwę.
Kodowanie semantyczne w Visual Studio z pluginem AssistX
O co w nim chodzi? Standardowe kolorowanie potrafi między innymi odróżnić słowa kluczowe od identyfikatorów, wyróżniając zwykle te pierwsze innym stylem czcionki, zaś te drugie pozostawiając bez zmian. Wszystkie identyfikatory: nazwy zmiennych, funkcji, typów, stałych, szablonów, itp., są więc formatowane tak samo i wyglądają identycznie.
Trik kolorowania semantycznego polega właśnie na rozróżnieniu tych wszystkich kategorii identyfikatorów. Oczywiście jest to możliwe tylko wtedy, gdy IDE dysponuje bazą danych o całej strukturze projektu. Ale taka baza jest przecież coraz częściej tworzona, tyle że w innym celu: zapewnienia automatycznego uzupełniania poprzez mechanizmy w rodzaju IntelliSense w Visual Studio. Na szczęście ktoś kreatywny wpadł na pomysł, że można ją wykorzystać także w inny sposób – i chwała mu za to :)
Kolorowanie semantyczne ma przynajmniej dwie zalety. Ułatwia ono zorientowanie się w przeglądanym kodzie, zwłaszcza takim który widzimy po raz pierwszy. Ponadto zaś pozwala ono na wczesne wykrycie prostych acz uciążliwych błędów w rodzaju literówek. Sprawiają one bowiem, że dany identyfikator – jako nieznany – jest kolorowany inaczej, co pozwala na łatwiejsze dostrzeżenie pomyłki.
A wady? Jak każdy mechanizm działający w tle, kolorowanie semantyczne zjada trochę zasobów systemowych – m.in. dla niego opłaca się mieć w procesorze więcej niż jeden rdzeń. A poza tym można zwyczajnie nie lubić pstrokatego kodu i preferować bardziej jednolitą kolorystykę… O gustach się przecież nie dyskutuje, a teoretycznie kodować można i w Notatniku :)
Jakiś tydzień temu naszła mnie ochota, by zagrać sobie znowu w “jedynie słusznego MMORPG-a”, czyli sławetny World of Warcraft. Ciężko powiedzieć, dlaczego, skoro przez prawie 10 miesięcy nie chciało mi się tykać tej gry nawet końcem małego palca… Pewnie dobrą wymówką będą wakacje – krótkie wprawdzie, ale jednak :)
Wnioski z ponownego odwiedzenia wirtualnego świata WoW są, ogólnie mówiąc, różne i ciekawe zarazem. Najważniejszą obserwacją jest chyba to, co ktoś nazwał coraz większym “zcasualowaniem się” tej gry, a ja określam mianem “syndromu zbliżającego się dodatku”. (Drugi expansion pack do tej gry wejdzie właśnie niedługo w fazę beta-testów, na które można się już zapisywać). W skrócie polega to na tym, iż wszystkie elementy gry określane zgrabnie jako endgame – czyli te najtrudniejsze i najbardziej wymagające – są teraz znacznie bardziej dostępne nie tylko dla 5 czy 10 procent hardcore‘owych graczy. Lokacje, które kiedyś wymagały dobrze skoordynowanej drużyny 10 lub 25 osób (raidy), najlepiej z jednej gildii, są teraz w zasięgu grup formowanych spontanicznie z graczy w gruncie rzeczy mniej lub bardziej przypadkowych.
Jest to w sumie naturalna kolej rzeczy, że dodawany na bieżąco przez twórców gry content z czasem się dewaluuje, co skutkuje wprowadzeniem nowych lokacji, bossów, itp. – i tak to się zasadniczo kręci :) Wielkim problemem chyba wszystkich MMORPG-ów jest jednak schematyczność, bowiem po pewnym czasie (czasem dłuższym – zwłaszcza w przypadku tak dopracowanej gry jak WoW) stwierdzić można, że to wszystko tak naprawdę już było. Trochę inaczej, ale duże analogie są jednak widoczne.
Recykling pomysłów jest zauważalny zwłaszcza w przypadku walk z bossami, co jest esencją każdego raidu. Dla niewtajemniczonych wyjaśniam, że podstawowy schemat przebiegu takiej walki w klasycznym MMORPG-u typu fantasy wyróżnia trzy elementy, czyli role pełnione przez poszczególnych graczy:
Mało skomplikowane, prawda? W czystej wersji (zwanej wyjątkowo obrazowo tank & spank) byłaby to w istocie wielka nuda. Dlatego zawsze występują liczne dodatkowe atrakcje, których może być niewiele lub całkiem sporo, ale według mnie wpadają zawsze w jedną z czterech poniższych grup:
Jaki jest wniosek z tej nieco przydługiej wyliczanki? Ano taki, że w WoW-ie nowatorskie pomysły pojawiają się niestety coraz rzadziej. Spośród 17 przykładów, które mimochodem wymieniłem (tak, chodzi o te dziwne linki ;D), tylko cztery pochodzą z wydanego półtora roku temu pierwszego dodatku, The Burning Crusade. Wszystkie inne koncepty pojawiły się już w podstawowej wersji gry i są tylko użytkowane ponownie z niewielkimi zmianami.
Czy to oznacza niedaleki zmierzch jej popularności? To niewykluczone. Ale przecież zawsze pozostaje jeszcze rozgrywka typu Player vs Player. Tam tendencje są zgoła odwrotne – upraszczające, a najlepszych ich wyrazem są areny. Weźmy po prostu dwie drużyny składające się z 2, 3 lub 5 graczy i niech wygra lepsza. Mało oryginalne, ale zadziwiająco popularne :D