Być może czasami też używacie starego modelu obiektowego.
W obecnym projekcie używam, bo dają mi to samo co zaawansowane rekordy, ale dodatkowo można je dziedziczyć bez żadnych kombinacji z ich zawartością.
Osobiście należy do tych leniuchów, którzy uważają, że definiowanie klas do struktur manipulujących innymi strukturami jest niepotrzebną ornamentyką.
Jeśli tak uważają, to są w błędzie. Struktury, obiekty, klasy i interfejsy to nie jest ”ornamentyka”, a struktury danych charakteryzujące się konkretną funkcjonalnością. Gdyby było inaczej, to mielibyśmy do czynienia z cukrem składniowym, a nie mamy.
Nawiasem mówiąc zabawne, że w Delphi najpierw usunięto stary model obiektowy, ale potem nagle uznano, że są potrzebne zaawansowane rekordy.
Nie wiem na ile jest to prawda, ale zaawansowane rekordy nie są zamiennikiem klasycznego modelu obiektowego. Różnica między rekordami a obiektami jest taka, że obiekty wspierają dziedziczenie oraz VMT (opcjonalnie). Ale z drugiej strony, obiekty mogą być kompatybilne z najprostszymi rekordami — wystarczy nie inicjalizować VMT i voilà. Dziedziczenie nadal będzie zapewnione (na poziomie języka), ale rozmiar obiektu (na podstawie sumy rozmiaru jego pól) będzie identyczny jak w przypadku struktur.
Benefitem korzystania z obiektów zamiast z rekordów jest również to, że język zapewnia wbudowaną obsługę enkapsulacji zawartości, zamiast wymagać jej aktywacji za pomocą dyrektywy {$MODESWITCH ADVANCEDRECORDS}
.
Na forum Lazarusa twierdzą, że wstydzili się przyznać, że decyzja z obiektami była pochopna.
Znów, nie wiem na ile w tym prawdy, ale jeśli tak było, to zdecydowanie uznaję taką decyzję za pochopną. Pascal dorobił się bogactwa najróżniejszych struktur danych, których w innych językach nie ma. Mamy ich aż sześć:
- rekordy proste,
- unie, nazywane variant records (których składnia to jakiś smutny żart),
- rekordy zaawansowane,
- obiekty (klasyczny model OOP),
- klasy (współczesny model OOP),
- interfejsy.
Każda struktura danych w powyższej liście charakteryzuje się odmienną funkcjonalnością, w kolejności od najmniejszej do największej (interfejsów nie liczę). A skoro tak, to rezygnowanie z którejkolwiek byłoby czystą głupotą.
Zwykłe rekordy to najprostsze struktury przeznaczone wyłącznie do przechowywania danych, unie rozszerzają ich funkcjonalność o możliwość deklaracji pól pod jednym adresem (coś jak absolute
). Rekordy zaawansowane dodatkowo wspierają prostą hermetyzację (tylko private
i public
) i mogą zawierać metody. Co jednak istotne, wszelkie metody zadeklarowane wewnątrz typu rekordu nie są jego częścią i oznacza to, że rekord zawierający same metody de facto ma rozmiar 0
bajtów.
I tu wkraczają klasyczne obiekty. Te wspierają wszystko to co powyższe struktury, ale dodatkowo wspierają (mono)dziedziczenie oraz mogą (acz nie muszą) posiadać VMT. Jeśli programista potrzebuje najprostszych struktur danych, które mogą być dziedziczone i hermetyzowane (wszystkie sekcje oprócz published
), to powinien wybrać obiekty, bo są/mogą być zgodne pamięciowo z rekordami, ale dodatkowo ułatwiać pisanie kodu (wbudowane dziedziczenie i brak zabawy z dyrektywami). Poza tym, w odróżnieniu od klas, obiekty domyślnie alokowane są na stosie (ale mogą też być alokowane na stercie).
Klasy natomiast to najbardziej zaawansowane struktury danych, jakie natywnie wspierane są przez język. Wbudowana obsługa dziedziczenia z innych klas, wielodziedziczenia interfejsów, wbudowane VMT, pełna funkcjonalność hermetyzacji, RTTI itd. itd. Jest to najczęściej wykorzystywany model reprezentacji danych w typowych projektach, bo najbardziej zaawansowany, elastyczny i prosty w użyciu.
Wracając jednak do Free Pascala stary tryb obiektowy jest słabo udokumentowany (wiecie np., że właściwości działają, chociaż nigdzie nie ma nic na ten temat?).
Dokumentacja jest i ma się dobrze — Free Pascal, Chapter 5 (Objects). Są też materiały w wiki Free Pascala na ten temat.
Coś zacząłem poprawiać w kodzie i zrobiłem się nagle ciekawy czy ten model jest dalej rozwijany.
Chyba jest, a przynajmniej obecna forma jest nieco bardziej funkcjonalna niż ta np. z Turbo Pascala.
Dla przykładu, jest wsparcie dla sekcji strict private
i strict protected
, co nie jest udokumentowane i czego nadal nie rozumie completion box, bo listuje ich zawartość tam, gdzie nie ma do nich dostępu i gdzie kompilator zgłosi błąd identifier idents no member
. ;)
A metody generyczne? I wiecie co? Kompiluje się w FPC 3.2.2…
Nie ma powodów, aby się nie kompilowały — składnia kodu jest jak najbardziej prawidłowa. Jedyne co kłuje w oczy to ten cholerny specialize
, ale tak zostały pierwotnie zaprojektowane generyki we Free Pascalu. Ale zawsze można włączyć automatyczną specjalizację, za pomocą dyrektywy {$MODESWITCH IMPLICITFUNCTIONSPECIALIZATION}
, choć w oficjalnej wersji FPC/Lazarusa, ten przełącznik jeszcze nie jest wspierany.