Monthly archive for January, 2008

Własności właściwości

2008-01-08 21:28

Niezastąpionym rodzajem składników klas są pola i metody, ale większość języków umożliwia też dodawanie również innych elementów. Ich głównym przeznaczeniem jest ułatwianie życia programiście i czynienie kodu bardziej czytelnym – pod takim rzecz jasna warunkiem, że są one odpowiednio użyte.
Do tej szuflady wpadają na przykład właściwości. Są to takie składniki klas, które wyglądają jak zmienne, lecz w rzeczywistości za pobieraniem i ustawianiem ich wartości może kryć się bardziej skomplikowany kod niż tylko proste odwołanie do zmiennej.

Okienko właściwości w Visual StudioSpośród mainstreamowych języków prawdopodobnie najwygodniejszy mechanizm właściwości występuje w C#:

  1. public int Width
  2. {
  3.    get { return rect.Width; }
  4.    set { rect.Width = value; }
  5. }

Ważną cechą właściwości jest też to, aby możliwe było tworzenie takowych w wersji tylko-do-odczytu. Tutaj wystarczy pominąć frazę set.
Dla kontrastu w Javie właściwości nie ma… w ogóle :) Mimo to narzędzia do wizualnego tworzenia aplikacji radzą sobie całkiem nieźle w odczytywaniu funkcjonalności komponentów, posługując się tzw. JavaBeans. W skrócie jest to pewien mechanizm oparty na refleksjach (odczytywaniu informacji o klasie w kodzie programu) i specyficznej konwencji nazywania metod dostępowych. Oczywiście nawet najlepsze nazwy nie zrekompensują dziwnej składni takich “właściwości”, ale sam pomysł trzeba uznać za dosyć udany.
W Delphi w zasadzie też trzeba tworzyć metody dostępowe, lecz można je podpiąć pod faktyczne właściwości:
[delphi]type TFoo = class
private
FNumber : Integer;
procedure SetNumber(const ANumber : Integer);
public
// właściwość
property Number : Integer read FNumber write SetNumber;
end;[/delphi]
Możliwe jest też, jak widać, bezpośrednie przełożenie właściwości na odpowiednią zmienną, która przechowuje jej wartość. Całkiem niezłe, chociaż wymaga to sporo pisania – co aczkolwiek jest charakterystyczną cechą Delphi :)

A cóż z naszym ulubionym językiem, czyli C++? Właściwości w nim oczywiście nie ma, chociaż w Visual C++ na przykład istnieje deklaracja __declspec(property), mająca podobne możliwości do słówka property z Delphi. Jeśli zaś chodzi o przenośne rozwiązanie, to można sobie wyobrazić obiekt “opakowujący” wskaźnik na pole lub metodę, który działałby jako symulacja właściwości – na przykład:

  1. public: PropertyGetSet<int> Number;

Przy użyciu kilku sztuczek z szablonami, wspomnianymi wskaźnikami i być może jakimś rozwiązaniem dla delegatów, taka implementacja jest zapewne możliwa. Istnieje aczkolwiek dość poważna niedogodność: taki obiekt opakowujący należałoby zainicjować w konstruktorze:

  1. public:
  2.    Foo() : Number(&Foo::GetNumber, &Foo::SetNumber) { }

zatem “deklaracja” naszej “właściwości” rozbita by została na dwa miejsca. A właściwie – na co najmniej dwa miejsca, bo w przypadku większej ilości konstruktorów rzecz wygląda nawet gorzej.

Technika ta będzie przydatna wtedy, gdy pola będziemy mogli inicjalizować w momencie ich deklaracji, co jest proponowane w C++0x. Wygląda więc na to, że znów dochodzimy do konkluzji, że język C++ pozostaje daleko w tyle w stosunku do swych młodszych braci. Ale czegóż można oczekiwać po staruszku, który w tym roku będzie obchodził swoje ćwierćwiecze? :) Zanim więc otrzyma on jakże konieczny lifting, musimy żyć z niezbyt wygodnymi, ale koniecznymi, metodami dostępowymi.
Hmm… A przecież chciałem dzisiaj ponarzekać raczej na Javę… No cóż, nie wyszło ;-)

Tags:
Author: Xion, posted under Programming » Comments Off on Własności właściwości

Efektywne stawianie pikseli

2008-01-07 22:00

Obecnie biblioteki graficzne umieją już bardzo, bardzo dużo. W narzędziach takich jak DirectX czy OpenGL mamy ogromne możliwości efektywnego wyświetlania grafiki trójwymiarowej, a jednocześnie ich obsługa staje się z kolejnymi wersjami coraz łatwiejsza. Należy oczywiście poznać nieco matematycznych podstaw stojących za całą grafiką 3D: przekształceniami, oświetleniem, buforem głębi, i tak dalej. Zasadnicza część – czyli cały potok renderowania oraz rasteryzacja – jest już jednak wykonana za nas.
Powiedzmy jednak, że nie zadowala nas ten stan rzeczy i ze względów edukacyjnych – lub możliwych czynników zewnętrznych :) – chcemy sami dowiedzieć (w sposób najbardziej praktyczny, czyli poprzez implementację), jak to wszystko działa. Wówczas do szczęścia potrzebujemy właściwie tylko jednej operacji: wyświetlenia pojedynczego piksela w określonym kolorze. I jest tylko jedno ale: aby to wszystko działało w jakikolwiek sensowny sposób, operacja ta musi być diabelnie szybka.

Niestety (a może właśnie ‘stety’) czasy, w których łatwo możemy pisać bezpośrednio po pamięci ekranu, najwyraźniej już dawno się skończyły. Nowoczesny system operacyjny nie pozwala po prostu na takie niskopoziomowe operacje żadnym programom użytkownika. Z drugiej strony korzystanie z tego, co w zakresie wyświetlania grafiki ów system oferuje, może być niewystarczająco – pod względem wydajnościowym, rzecz jasna.
Dlatego wydaje się, że do eksperymentów dobrze nadają istniejące biblioteki graficzne – tyle że ograniczone do jednej funkcjonalności: renderowania sprite’ów punktowych (point sprites). Polega ona na rysowaniu quadów (kwadratów złożonych z dwóch trójkątów) w taki sposób, że zawsze są one zwrócone przodem do kamery. Biorąc pod uwagę to, że wielkość takich punktów możemy określić, ustawienie jej na równą jednemu pikselowi sprawi, że wyświetlanie sprite’ów punktowych będzie dobrym substytutem “stawiania” pojedyncznych pikseli.
Gdzie w zakamarkach bibliotek graficznych ukryta jest tego rodzaju funkcjonalność? Otóż:

  • W DirectX należy ustawić stan renderowania D3DRS_POINTSCALEENABLE na FALSE (co zresztą jest domyślną wartością) oraz D3DRS_POINTSIZE na 1.0f, czyli wielkość odpowiadającą jednemu pikselowi. Co ciekawe, trzeci o nazwie D3RS_POINTSPRITEENABLE wbrew pozorom lepiej jest zostawić ustawiony domyślnie na FALSE. Nie dotyczy on bowiem (co jest dość mylące) samej możliwości rysowania sprite’ów punktowych, a jedynie sposobu mapowania współrzędnych tekstur – co w przypadku symulowania pikseli nie jest nam potrzebne.
    Po tych zabiegach wstępnych możemy rysować punkty, podając format wierzchołków z polami D3DFVF_XYZRHW oraz D3DFVF_DIFFUSE przy pomocy dowolnych wywołań DrawPrimitive[UP] z typem prymitywów D3DPT_POINTLIST.
  • W OpenGL nie musimy ustawiać niczego związanego specyficznie ze sprite’tami punktowymi (bo np. ich domyślna wielkość to 1.0f). Jeśli zaś chodzi o samo rysowanie punktów to jednym ze sposobów (i pewnie nie najlepszym :)) jest ustawienie wszystkich macierzy na jednostkowe i podawanie współrzędnych punktów jako wektorów 4D z ustaloną współrzędną Z (np. 0) oraz W równą 1, do funkcji glVertex4*. Musi być ona umieszczona oczywiście między glBegin (z parametrem GL_POINTS) a glEnd, zaś kolor punktu-piksela określić możemy przez glColor*.

Jak widać, mechanizmy wspomagające nas w ręcznej, pikselowej robocie są nieco ukryte. Co więcej, w DirectX 10 na przykład sprite’y punktowe zostaną wyeliminowane z biblioteki i konieczne będzie samodzielne tworzenie odpowiednich quadów, jeśli zechcemy uzyskać podobną funkcjonalność. To prawdopodobnie słuszna decyzja, bowiem nawet w swoim głównym zastosowaniu – czyli systemach cząsteczkowych – są one zbyt ograniczone (choćby dlatego, że są cały czas zwrócone do kamery, co wyklucza możliwość obrotu cząstek). A przyznajmy, że samodzielne stawianie “pikseli” jest dość egzotyczne – co nie znaczy, że nie warto wiedzieć, jak to się robi, jeśli kiedykolwiek będzie to nam potrzebne…

Tags: , , ,
Author: Xion, posted under Programming » 2 comments

Całe to Web 2.0

2008-01-05 17:44

Wraz początkiem tego roku minęło okrągłych 8 lat, od kiedy to po raz pierwszy zajrzałem w to “coś”, co nazywamy Internetem. Nie były to z jednej strony bardzo zamierzchłe czasy. Strony WWW były oczywiście bardziej statyczne i mniej wypełnione obrazkami (mała przepustowość łącz!), ale nie wyglądały wcale ubogo. Tak chętnie używane teraz komunikatory również istniały i były całkiem popularne – na czele z dzisiaj już trochę zapomnianym ICQ.
Z drugiej jednak strony wydaje się, że tamten okres jest już prehistorią. I nie chodzi tu tylko o znaczne zwiększenie szybkości dostępu do sieci, do poziomu pozwalającego chociażby oglądać filmy streamowane w czasie rzeczywistym. Prawdopodobnie ważniejszą zmianą jest bowiem jego upowszechnienie oraz to, co z tego wynikło: zmiana podejścia do Internetu, które to od kilku lat określa się supermodnym terminem ‘Web 2.0’.
Logo w stylu Web 2.0Jako że jest to pojęcie bardzo na czasie, bywa ono nadużywane i dlatego nie bardzo poddaje jednoznacznemu zdefiniowaniu. Sam zazwyczaj rozumiem je jako taką zasadę działania Internetu (chociaż dotyczy to prawie wyłącznie WWW), w myśl której to użytkownicy są nie tylko odbiorcami, ale i głównymi (a często i jedynymi) twórcami treści.

Mamy więc łatwość jej tworzenia oraz szeroki dostęp do sieci. Co powstaje z połączenia tych dwóch czynników?… Rezultaty są, mówiać oględnie, bardzo różne. Widać rzecz jasna “inteligencję tłumu”, której największym dziełem jest zapewne Wikipedia – chociaż równie cenna jest cała masa innych serwisów tematycznych, współtworzonych przez swoich gości. Przy bliższym spojrzeniu można jednak łatwo zauważyć, że wszystkie te twory funkcjonują i są wartościowe głównie dlatego, że ktoś zawsze nad nimi czuwa i dba o ich jakość. Bez ciągłej opieki wszystko ulega bowiem degeneracji. Analogicznych zjawisk można się dopatrzeć niemal wszędzie, od ekonomii (zły pieniądz wypiera dobry) po fizykę (entropia układu nigdy nie maleje), serwisy spod znaku Web 2.0 też nie są od nich wolne. Wręcz przeciwnie: konieczna jest systematyczna i niemająca końca praca autorów, poprawiających artykuły zamieszczone na wiki, czy moderatorów dbających o poziom dyskusji na forach. Próbkę tego, w jakim kierunku podążyłaby cała sieć bez tej pracy, można zobaczyć, oglądając komentarze pod artykułami na dowolnym internetowym portalu.

W sumie jednak nie jest to nic nowego: trolle na grupach dyskusyjnych istnieli pewnie od zarania Usenetu i kolejna forma ich “ewolucji” była zupełnie do przewidzenia. Podobnie większość z rozwiązań określanych teraz mianem Web 2.0 istniało na długo przed ukuciem tego terminu (w 2004 roku). Jednak dopiero po jego powstaniu ujrzeliśmy cały wysyp pomysłów, których twórcy zaczęli ideę Web 2.0 intensywnie wcielać w życie.
Logo serwisu TwitterEfektem tego są na przykład różne ‘ciekawe’ serwisy i usługi, których przeznaczeniem jest wymiana ‘informacji’ między użytkownikami. Zaczynają się one od takich, przez które możemy poinformować znajomych o tym, co aktualnie robimy, zaś kończą na wielofunkcyjnych i rozbudowanych serwisach ‘społecznościowych’. Można tam stworzyć swój profil, zamieszczać zdjęcia, tworzyć listy znajomych, a nawet dyskutować na forach. Zadziwiające, prawda?…
Logo MySpaceRzeczywiście, przynajmniej dla mnie jest zupełnie niewytłumaczalne, na czym polega fenomen popularności takich miejsc. Wystarczy bowiem zadać jedno proste pytanie, by zakwestionować cały sens ich istnienia. Brzmi ono: “No i co z tego?”. No właśnie – czy mamy w tym przypadku do czynienia z jakimiś genialnymi pomysłami? Przecież to wszystko już było: dla każdego takiego serwisu (oraz każdej jego funkcji) można z łatwością znaleźć istniejącą usługę sieciową – lub jej część – która potrafi mniej więcej lub nawet dokładnie to samo.
Logo serwisu nasza-klasa.plTrik zatem polega najprawdopodobniej na zintegrowaniu tego wszystkiego i odgadnięciu sposobu myślenia przeciętnego użytkownika Internetu, dla którego sieć zaczyna się i kończy w przeglądarce WWW. Nadal jednak nie wyjaśnia to gigantycznej liczby użytkowników tego rodzaju stron.

Kiedyś mieliśmy serwisy, wokół których – jeśli były popularne – tworzyły się społeczności, przyczyniające się do poprawy ich jakości i wytyczające ścieżki dalszego rozwoju. Teraz mamy serwisy społecznościowe, którego niczego nie poprawiają i nie przyczyniają się do niczyjego rozwoju…
Jakie więc może być dalszy kierunek zmian? Może sparafrazujmy Einsteina: mówił on, że nie wie, jak będzie wyglądała III wojna światowa, ale IV zapewne będzie na kije i pałki. My zaś nie mamy jeszcze zbytniego pojęcia, czym bedzie Web 3.0 – więc kto wie, czy z kolei wersja 4.0 nie będzie polegać na czymś podobnym? ;-)

Tags:
Author: Xion, posted under Internet, Thoughts » 4 comments

Odwracanie macierzy 4×4

2008-01-04 20:54

Do napisania czegokolwiek z dziedziny programowania gier lub grafiki potrzebna jest zawsze chociaż skromna biblioteka, zawierają podstawowe obiekty matematyczne. Jej częścią na pewno muszą być wektory, a nie od rzeczy są także macierze, kwaterniony, obiekty reprezentujące linie i płaszczyzny, i tak dalej. Taką bibliotekę zwykle albo pisze się raz, albo wykorzystuje jedną z już istniejących. Jakikolwiek byłby nasz wybór, mogłoby się wydawać, że sprawę z nią można załatwić raz na zawsze.
Cóż, nic bardziej błędnego :) Możemy być oczywiście bardzo przywiązani do narzędzi, którymi się posługujemy – języka programowania, platformy, itd. – ale kiedyś na pewno przyjdzie nam zmierzyć się z zupełnie innym językiem i innym środowiskiem. A wtedy trzeba jakoś ten problem matematycznej biblioteki rozwiązać choćby na szybko.

Ostatnio przytrafiło mi się właśnie coś takiego. Nie jest to naturalnie nic pasjonującego, bowiem implementowania dodawania, odejmowania czy mnożenia wektorów jest zajęciem raczej nużącym. Jednak okazało się, że istnieje przynajmniej jedna potrzebna, a niezbyt oczywista matematyczna operacja, którą należy koniecznie uwzględnić. To odwracanie macierzy.
Chcąc tego dokonać programowo, możemy wykorzystać na przykład któryś z tych trzech sposobów:

  • Metoda bezpośrednia. Jest to prostu zaimplementowanie ręcznego sposobu odwracania macierzy, wykorzystywanego zazwyczaj w połączeniu z kartką i długopisem :) Dla tych, co przysypiali na wykładach z algebry (lub nie mieli jeszcze szczęścia na nie uczęszczać ;)) przypominam, że polega to na wykonaniu określonych operacji (mnożenia przez liczbę oraz dodawania) na wierszach naszej macierzy oraz jednocześnie na wierszach macierzy jednostkowej. W ich wyniku nasza macierz sama ma zmienić się w jednostkową, zaś ta druga będzie wtedy szukaną odwrotnością. Wiadomo skądinąd, że złożoność tego algorytmu to O(n3), gdzie n to wymiar macierzy.

    Ręczne odwracanie macierzy

  • Rozwiązanie układów równań. Ta metoda wymaga posiadania procedury rozwiązującej układy równań, jak na przykład eliminacji Gaussa lub znajdowania rozkładu LU. Posługując się nią, możemy obliczyć kolejne wiersze macierzy odwrotnej i też zajmie nam to czas O(n3). Oczywiście trzeba jeszcze mieć (tj. napisać) rzeczoną procedurę, co już takie proste nie jest :)
  • Dopełnienie algebraiczne. Ten sposób charakteryzuje się głównie tym, że wymaga obliczenia sporej liczby wyznaczników – nie tylko tej macierzy, którą odwracamy, ale i każdej z jej podmacierzy. Wiadomo zaś, ze wyliczanie wyznaczników nie należy do operacji tanich. W istocie złożoność tej metody odwracania leży gdzieś w okolicach wykładniczej.

Trzeba jednak zauważyć pewną rzecz. Otóż do celów graficznych potrzebujemy jedynie macierzy o stałym rozmiarze, i to niewielkim – zwykle 4×4. Przy tak małym rozmiarze danych złożoność algorytmu (która niejawnie zakłada, że rozmiar ten jest bardzo duży) nie jest miarodajna. Liczy się bowiem dokładna ilość faktycznie wykonywanych operacji. A przy takim podejściu spotyka nas niespodzianka, jako że najwyraźniej najlepsza okazuje się metoda ostatnia. Jest ona używana na przykład w funkcji D3DXMatrixInverse, zatem posiada całkiem dobrą rekomendację :)
I ma chyba tylko jedną wadę. Po rozpisaniu występującej w niej pętli (co jest możliwe, jeśli znamy z góry rozmiar macierzy) zamienia się ona w dość odstraszającą szpaltę kodu z kilkunastoma długimi, niemal identycznie wyglądającymi wierszami, które różnią się tylko permutacją cyferek oraz plusów i minusów. Ale przecież tak wygląda kod w zasadzie każdego działania na macierzach i właśnie dlatego tak lubimy je implementować ;-)

Tags:
Author: Xion, posted under Programming » 3 comments

A.I. – wariacja na temat

2008-01-04 0:36

Zawsze byłem sceptycznie nastawiony do tak zwanej ‘sztucznej inteligencji’. Nie chodzi tu bynajmniej o stosunkowo proste algorytmy klasyfikowane dość swobodnie i niezbyt formalnie jako AI, a wykorzystywane chociażby w programowaniu gier: wyszukiwanie najkrótszej drogi, zachowanie się postaci typu NPC, itp. Mam raczej na myśli takie konstrukcje (zarówno programy, jak i urządzenia, a najczęściej połączenie jednych i drugich), które starają się być znacznie bardziej uniwersalne i sprawiać wrażenie inteligentnych w jakimkolwiek z spośród licznych i niezbyt jasnych znaczeń tego słowa.
Mój “problem” polegał mniej więcej na tym, że jakoś ciężko było mi uwierzyć w to, że kiedyś – nawet niekoniecznie w przewidywalnej przyszłości – maszyny będą rzeczywiście myślały. Można to uznać za swego rodzaju zawodowe zboczenie. Wiedząc, że komputery działają zawsze w oparciu o określony, niezmienny i ściśle zdefiniowany algorytm, trudno jest uwierzyć, że wystarczy tylko odpowiedni wzrost mocy obliczeniowej, by nagle zyskały one jakieś nieprzewidziane zdolności. W takim podejściu tkwi jednak pewne dość wątpliwe, a kluczowe założenie, o istnieniu którego zdałem sobie sprawę dopiero niedawno…

Robot Kismet
Kismet – robot “z uczuciami”
© Jared C. Benedict, MIT

Zasadniczo z maszynami, które mają być w jakimś aspekcie podobne do ludzi lub innych istot żywych, wiążą się dwa zasadnicze problemy. Pierwszym jest różnica między właściwościami, jakie faktycznie posiadają, a tymi, które tylko wydają się posiadać. Nietrudno na przykład zauważyć, że spsiały robot Aibo całkiem dobrze naśladuje zachowanie prawdziwego zwierzęcia. Równie szybko można jednak zdać sobie sprawę, że tak naprawdę nie zrobi on niczego, do czego nie został wcześniej zaprogramowany. Nawet jeśli ktokolwiek przypisuje mu więc jakiekolwiek psie cechy, nie czyni go to jeszcze sztucznym psem.
Drugim i znacznie poważniejszym problemem jest to, że konstruując tego rodzaju maszyny, ludzie starają się naśladować coś, o czym tak naprawdę wiedzą niewiele. Wciąż nie mamy dobrych (czyli weryfikowalnych) definicji na takie pojęcia jak ‘życie’, ‘inteligencja’ czy ‘świadomość’. Zwłaszcza ten ostatni termin jest kłopotliwy, gdyż stuprocentowo pewną odpowiedź pozytywną na pytanie “Czy coś jest świadome?” możemy udzielić tylko wtedy, gdy chodzi o… nas samych.

I chociaż filozofia jak zwykle nie dostarcza żadnych konkretnych odpowiedzi, nie przeszkadza to badaczom dociekać, jak świadomość może powstawać – ze szczególnym uwzględnieniem ludzkiej, która musiała przecież wykształcić się w toku ewolucji. Do niedawna najlepszym “wyjaśnieniem”, o jakim słyszałem, była emergencja, czyli powstawanie złożonych zjawisk na kanwie prostych “klocków”. Innymi słowy jest to twierdzenie, że całość jest czymś więcej niż tylko sumą części. W odniesieniu do świadomości oznacza to, że w dostatecznie dużym zbiorze neuronów (albo odpowiednio zaawansowanym komputerze czy też sieci tychże) wyłoni się ona samoistnie. Raczej mało przekonujące, nieprawdaż?
Znacznie ciekawszym przypuszczeniem jest hipoteza, że ludzie są samoświadomi, gdyż używają w stosunku do swojej osoby pewnych modeli, które są wykorzystywane przez mózg w odniesieniu do innych ludzi. Zakładamy na przykład, że inni ludzie też myślą, mają uczucia i że w swoim postępowaniu kierują się jakimiś zasadami. Często takie założenia i oparte na nich modele zachowań bywają trafne, więc przez pokolenia były udoskonalane, bo miały po prostu ewolucyjne uzasadnienie. Ciekawie zaczyna się robić wtedy, kiedy odkrywa się, że z pomocą tzw. neuronów lustrzanych ludzki mózg może budować modele swego posiadacza. Właśnie taki model może być jeśli nie samoświadomością, to przynajmniej jej solidną podstawą.

Uff, to było wyczerpująca dygresja ;-) A jakie są praktyczne wnioski dla sztucznej inteligencji? Otóż jeśli świadomość rzeczywiście tak “działa”, to można nią obdarzyć dowolny byt w relatywnie łatwy sposób. Wystarczy, że będzie on posiadał jakiś mechanizm, umożliwiający mu rozpoznawanie innych bytów, a następnie zastosuje go w stosunku do siebie.
Proponuję teraz zejść wreszcie z tych niebotycznych wyżyn abstrakcji – i to od razu na sam dół: do kodu. Napiszmy po prostu klasę obiektów, które będą świadome w powyższym sensie:

  1. class ConciousObject:
  2.     def perceive(self, obj):
  3.         if (obj != self):
  4.             print "`" + str(obj) + "` is a(n) " + str(obj.__class__)
  5.         else:
  6.             print "I am a(n) " + str(self.__class__)
  7.  
  8.     def introspect(self):
  9.         self.perceive(self)

Tak, to już jest to. To chyba najbardziej prymitywny sposób realizacji całego pomysłu, ale zawiera wszystkie niezbędne elementy. Mamy tutaj metodę perceive, za pomocą której nasz obiekt może “postrzegać” jakiś inny obiekt – co tutaj oznacza po prostu wypisanie jego tekstowej reprezentacji wraz z nazwą jego klasy. Przejawem samoświadomości jest z kolei metoda introspect, która to pozwala obiektowi “postrzegać” w ten sposób siebie. Robi to podobnie jak we wszystkich pozostałych przypadkach, acz nieco inaczej, gdyż wie (tak jak ludzie), że teraz “patrzy” do swojego wnętrza. Mechanizm jest jednak podobny.
A przykładowe wyniki są następujące:

`42` is a(n) <type ‘int’>
`Ala ma kota` is a(n) <type ‘str’>
`<Foo instance at 0x014BDA08>` is a(n) Foo
I am a(n) ConciousObject

To oczywiście tylko żart, ale jeśli wspomniana teoria samoświadomości zdobędzie solidne dowody, to kto wie – może na analogicznej zasadzie będą w przyszłości konstruowane maszyny, które nie tylko myślą, ale też wiedzą, że myślą. Jeżeli bowiem świadomość jest tylko złudzeniem, to być może da się ten artefakt funkcjonowania mózgu zaimplementować także u maszyn.
W każdym razie mam nieodparte wrażenie, że zanim prawdziwego rozpędu nabierze rozwój sztucznej inteligencji, ja zdołam wyprodukować jeszcze sporą ilość podobnych “naturalnych głupot” ;-)

Tags:
Author: Xion, posted under Computer Science & IT, Thoughts » 7 comments

Niemal standardowe nazwy klas

2008-01-02 13:48
Model-View-Controller
Model-View-Controller (MVC),
bardzo modny ostatnio ‘wzorzec’

Wzorce projektowe (design patterns) to w założeniu ogólne modele związków pomiędzy klasami (i samych klas), jakie mogą pojawiać się w projektach. Każdy taki wzorzec jest przeznaczony do dość ściśle określonych okoliczności, dokładnie opisany i, przede wszystkim, nazwany. Na pewno każdy średnio zaawansowany programista miał okazję spotkać się z takimi terminami jak Iterator, Fabryka czy Singleton. Są one już na tyle długo używane, że w większości przypadków nie ma problemów ze zrozumieniem tego, co w danej sytuacji oznaczają.

Wzorce nie są oczywiście doskonałe. Ze względu na względnie dużą ścisłość nie mogą opisywać wszystkich rozwiązań, jakie mogą być konieczne, jeśli myślimy o zaprojektowaniu dowolnego programu. Nie jest więc tak, że każda klasa, jaka przyjdzie nam głowy, może być od razu wpasowana w jakiś gotowy szablon.
Przeglądając gotowe kody i różnego rodzaju dokumentacje stwierdziłem jednak, że często powtarzają się w nich różnego rodzaju “pseudowzorce”. Objawiają się one głównie używaniem pewnych słów w nazwach klas, dzięki którym można mniej więcej domyślić się, jaka jest rola poszczególnych typów, do czego służą, jak – z grubsza – działają oraz jakie wykazują zależności z innymi klasami. Naturalnie mogą występować spore różnice pomiędzy poszczególnymi bibliotekami i językami, ale przynajmniej dla dwóch największych zbiorów klas, jakie są obecnie w powszechnym użyciu (czyli .NET Framework i JDK), rozbieżności nie są zbyt duże. Co więcej, ponieważ wielu programistów używa któregoś z tych dwóch narzędzi, często przejmują oni te wzorce nazewnictwa (świadomie lub nie) i stosują je we własnych kodach. Kto wie, może dzięki temu przeciętna czytelność kodu produkowanego przez statystycznego programistę (jeśli w ogóle istnieje ktoś taki :]) ma szansę choć odrobinę wzrosnąć?…

Jakie są więc te nieformalne “wzorce”? Otóż znalazłem kilka następujących:

  • Manager to egzemplarz występujący bardzo często i niestety chyba najmniej jednoznaczny z nich wszystkich. W dosłownym tłumaczeniu jest to ‘zarządca’ czegoś i właściwie niewiele więcej można o nim powiedzieć. Nazywanie wszystkiego ‘menedżerem’ jest popularne zwłaszcza wśród programistów gier: mamy więc menedżery zasobów, tekstur, stanów, czcionek – i tak dalej. Zastanawiam się tylko, skąd to upodobanie to tego akurat terminu. Czyżby programiści z sentymentem wspominali w ten sposób Menedżera Programów, czyli sławetną “powłokę” systemu Windows w archaicznych wersjach 3.x? :)
  • Handler (ew. listener) jest już znacznie precyzyjniejszym pojęciem. Zazwyczaj jest to bowiem obiekt, który ma wykonywać jakieś działanie w reakcji na określenie zdarzenie – czyli ma je ‘obsługiwać’. Najczęściej oznacza to, że typ handlera jest tylko abstrakcyjną klasą bazową lub interfejsem, po którym powinniśmy dziedziczyć, a następnie zaimplementować jego metody i wreszcie “podpiąć” powstały obiekt pod mechanizm obsługi zdarzeń. Typowym zastosowaniem takiego rozwiązania jest reakcja na zdarzenia interfejsu użytkownika (klikanie w przyciski, wciśnięcia klawiszy, itd.) albo powiadamianie o przebiegu operacji asynchronicznych (np. komunikacji sieciowej).
  • Provider jest z kolei obiektem, który ma ‘dostarczać'(lub ‘zapewniać’) jakąś funkcjonalność. Od strony technicznej często działa on tak samo jak handler (czyli w oparciu o polimorfizm metod wirtualnych), tyle że jego przeznaczenie i sposób użycia są nieco inne. Takiego providera podajemy w funkcji lub w obiekcie, dzięki czemu może ona wykonać przy jego pomocy jakieś czynności. Prostym przykładem jest chociażby sortowanie, któremu podajemy obiekt komparatora, odpowiedzialny za dokonywanie porównań. Tak naprawdę jest to więc po prostu wzorzec Strategia (Polityka – policy), któremu ktoś z niewiadomych powodów nadał bardziej “profesjonalną” nazwę.
  • Context oznacza najczęściej taki obiekt, który definiuje jakieś ‘środowisko’, w którym działają inne obiekty. Są one zależne od obiektu reprezentującego kontekst, ale nie można powiedzieć, aby ten się z nich składał (może on nawet “nie wiedzieć”, że jest przez nie wykorzystywany). Po prostu dzięki niemu obiekty “potomne” mogą wykonywać swoje czynności.

Prawdopodobnie dałoby się wyróżnić jeszcze kilka pozycji (chociaż część byłaby dokładnym odpowiednikiem klasycznych wzorców projektowych), ale, jak widać, w sumie chyba nie jest ich zbyt dużo. To w gruncie rzeczy całkiem dobra wiadomość, gdyż nietrudno zauważyć, że wszystkie te nazwy są raczej “magiczne” i na pierwszy rzut nie przywołują jakichś natychmiastowych skojarzeń – zwłaszcza, jeśli nie jesteśmy do nich przyzwyczajeni. Ale taki już urok projektowania zorientowanego obiektowo, polegającego na tworzeniu dziwnych bytów i jeszcze dziwniejszych zależności między nimi :)

Tags: ,
Author: Xion, posted under Programming » 4 comments
 


© 2023 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.