Posts tagged ‘reflection’

Klasy bardziej meta

2011-11-08 21:57

W językach ze skrzywieniem obiektowym klas używa się często i gęsto. Nieco inaczej jest z innym, o wiele mniej znanym pojęciem: metaklasami. Przedrostek meta- sugeruje tu od razu nieco wyższy poziom abstrakcji, co jest generalnie słusznym podejrzeniem. Dokładne znaczenie kryjące się za tym terminem w pewnym stopniu zależy od języka programowania, lecz w każdym przypadku chodzi o narzędzie związane z manipulowaniem samymi klasami. Zupełnie intuicyjnie jest to więc “jeden poziom meta więcej” :)
Jako nieco bardziej zaawansowana funkcjonalność, metaklas nie wykorzystuje się codziennie. Tym bardziej jednak warto wiedzieć przynajmniej z grubsza, jak działają, aby poprawnie rozpoznawać sytuacje, w których są one użyteczne. I dlatego właśnie dzisiaj przyjrzymy się metaklasom w trzech wariantach, specyficznych dla popularnych języków programowania.

Pierwszy z nich dotyczy systemów refleksji, czyli przydatnego mechanizmu językowego, pozwalającego programowi na wgląd w swoją wewnętrzną strukturę. W językach obiektowych oznacza to przede wszystkim możliwość posługiwania się klasami na bardziej dynamicznym poziomie. Są one wtedy reprezentowane przez obiekty, i właśnie te reprezentacje – używane poprzez moduły refleksji – nazywa się czasem metaklasami.
W wielu językach wyglądają one podobnie. Java ma na przykład klasę java.lang.Class, zaś C# – System.Type. Zyskując dostęp do instancji tychże klas (np. poprzez Class.forName albo Type.GetType) otrzymujemy możliwość wykonywania operacji na klasach, które one reprezentują. I tak możliwe jest chociażby tworzenie ich obiektów, wywoływanie metod, dostęp do pól. Dzięki temu możemy na przykład w (miarę) łatwy sposób zaimplementować proste rozwiązania wspierające pluginy, tj. dynamicznie ładowane wtyczki do naszych aplikacji.

Drugie znaczenie pojęcia metaklasy opisuje referencje do klas. Ideą jest tu traktowanie klas jako wartości pierwszego rodzaju (first-class value), które można przypisywać do zmiennych i w uogólniony sposób przekazywać między różnymi miejscami w kodzie. Specjalne zmienne, do których możemy “przypisywać” klasy są w co najmniej jednym języku nazywane właśnie metaklasami.
Przydatność tego typu rozwiązania zależy głównie od tego, jak wielkimi jesteśmy fanami wzorców typu fabryka abstrakcyjna :) Być może podstawową funkcjonalnością takich metaklas jest bowiem abstrakcja procesu tworzenia (lub ogólniej: pozyskiwania z zewnątrz) nowych obiektów. Pozostałe przypadki użycia metaklas są pokrywane zwykle przez szablony (C++), typy generyczne (C#, Java, itp.) lub podobne mechanizmy tworzenia kodu, który w pewien określony sposób jest niezależny od dokładnego typu obiektów, którymi operuje.

Czas wreszcie na trzeci wariant metaklas. Jest on zdecydowanie najciekawszy, ale też najbardziej skomplikowany i w pewien sposób wysublimowany – mimo swojej niewątpliwej użyteczności. Mam tutaj na myśli metaklasy w Pythonie.

Tags: , , , , ,
Author: Xion, posted under Programming » 1 comment

Refleksje

2007-11-23 22:19

Dzisiaj zastanowimy się nad refleksjami. Nie, nie jest to wcale masło maślane. Mechanizm refleksji (reflection – odbicie) jest zwany też introspekcją i polega na tym, iż działający program “wie” o swojej wewnętrznej strukturze. Prostą odmianą jest tutaj dynamiczna informacja o typie (RTTI), czyli możliwość określenia faktycznego typu obiektu znanego poprzez wskaźnik lub referencję.
W bardziej zaawansowanej wersji, obecnej na przykład w języku Java i na platformie .NET, refleksje są jednak czymś więcej. Stanowią faktyczne ‘odbicie’ struktury programu w postaci informacji dostępnych w czasie wykonania. Przy ich pomocy można na przykład uzyskać dokładne informacje o polach, metodach i właściwościach każdej klasy oraz jej miejscu w hierarchii dziedziczenia, nie mówiąc już o możliwości tworzenia jej instancji. Dostępność takich informacji umożliwia łatwe stworzenie modułu serializacji lub bardziej zaawansowanego odśmiecania pamięci, bazującego na przechodzeniu grafu odwołań między obiektami.

Ale C++ posiada tylko bardzo proste RTTI, które do takich celów jest daleko niewystarczające. Czy można jednak naprawić tę przypadłość? Jest na to kilka sposobów:

  • Można spróbować odczytać informacje debugowania generowane przez nasz kompilator. To może dawać kompletne informacje o wszystkich typach użytych w programie, ale ma dwie zasadnicze wady. Po pierwsze, wymaga kompilacji programu przynajmniej z pewnymi ustawieniami trybu debugowania także w wersji wydaniowej. A po drugie, jest w oczywisty sposób nieprzenośnie pomiędzy różnymi kompilatorami. Poza tym nie wydaje mi się, żeby było to proste rozwiązanie.
  • Innym podejściem jest odczytanie wszystkich danych bezpośrednio, czyli samodzielne przeanalizowanie kodu źródłowego i wygenerowanie na tej podstawie koniecznych informacji. Najpewniej wynikiem byłyby dodatkowy kod poddawany normalnej kompilacji. Wadą jest tu stopień skomplikowania: parsowanie kodu C++ łącznie z rozwijaniem dyrektyw preprocesora zdecydowanie nie jest prostym zadaniem. Ponadto proces kompilacji projektu stałby się bardziej złożony.
  • Jeżeli ktoś byłby dostatecznie zdesperowany, mógłby teoretycznie… stworzyć własny kompilator C++, obsługujący refleksje natywnie. Nie da się ukryć, że potrzeba by sporej siły, by zamachnąć się motyką na takie słońce :)
  • Wreszcie możliwe jest, aby programista podawał niezbędne informacje – zwykle jako kombinacja dziedziczenia i makr preprocesora. To podejście jest (stosunkowo) najprostsze w implementacji, ale zapewne najbardziej nieporęczne w użytkowaniu. Może być też podatne na błędy. Jednocześnie jednak ma największe szanse być przenośne i… działające :)

Gdybym aczkolwiek kiedyś cierpiał na dużą nadwyżkę wolnego czasu, to pewnie rozważyłbym implementację rozwiązania drugiego (lub jakiejś kombinacji rozwiązania drugiego i pierwszego, na przykład zlecającej rozwijanie makr programowi kompilującemu). Do tego czasu jednak C++ już dawno będzie posiadał wbudowany system refleksji ;)

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


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