furious programming
2017-09-19 19:55

Generyki we Free Pascalu coraz bardziej zaczynają mnie denerwować – straszanie toporny jest ten mechanizm… Pierwsza wkurzająca rzecz to sposób używania zmiennych, przechowujących referencje do list generycznych.


Dla przykładu – chcemy użyć listy generycznej do przechowywania instancji poniższej klasy:

type
  TEntry = class(TObject)
  {..}
  public
    Data: Integer;
  end;

Teraz deklaracja zmiennej dla listy. W stylu Delphi – ale z użyciem dostępnego typu kontenera – było by to tak jak poniżej, ale wyrzuci błąd kompilacji (treść w komentarzu):

var
  Entries: TFPGObjectList<TEntry>;  // Error: Generics without specialization cannot be used as a type for a variable

No dobrze, dodajmy magiczne słówko spezialize:

var
  Entries: spezialize TFPGObjectList<TEntry>;

Taki kod zostanie poprawnie skompilowany, jednak nie mam zielonego pojęcia skąd mam teraz wydłubać konstruktor, aby utworzyć instancję takiej listy. Nie mam określonego typu danych (jawnej klasy), więc trzeba by jakiejś magii, może ze słówkiem specialize, może z generic, a może z czymś innym, jednak różne konfiguracje zawodzą.

Pewnym obejściem jest po prostu zadeklarowanie osobnego typu, z którego będzie możliwe wywołanie konstruktora:

type
  TEntries = specialize TFPGObjectList<TEntry>;
var
  Entries: TEntries;
begin
  Entries := TEntries.Create();
  {..}

No i fajnie – kod się kompiluje, listę da się utworzyć. Po problemie? Nie… :]


Tak utworzona klasa TEntries co prawda potrafi już przechowywać obiekty klasy TEntry, jednak dostęp do nich jest nieco utrudniony. Załóżmy, że chcemy uzyskać dostęp do pierwszego obiektu listy i np. wpisać dane do zmiennej TEntry.Data. Odpowiedni zapis wygląda tak:

Entries[0].Data := $FF; // lub Entries.Items[0].Data := $FF;

Kod jest poprawny, kompiluje się, działa. Gdzie jest problem? W domyślnej właściwości Items. W klasie TFPGObjectList zdefiniowana jest w taki sposób, że zwraca lub modyfikuje T, czyli nie wiadomo co:

property Items[Index: Integer]: T read Get write Put; default;

Kompilator nie widzi problemu i najwyraźniej podczas kompilacji pod to T podstawia sobie klasę, której obiekty moja lista przechowuje. Jednak mechanizm kompletowania kodu gubi się – po klepnięciu kropki po nawiasach z indeksem elementu, powinno pojawić się okienko completion box i coś podpowiedzieć, ale wyrzuca błąd:

Entries[0].  // Error: illegal qualifier . found

Zapewne mechanizm ten dalej widzi typ elementu jako T (no bo tak jest zdefiniowany w klasie bazowej), więc nie może nic podpowiedzieć, a że pisanie kodu bez funkcji kompletowania jest niewygodne, dlatego też trzeba to naprawić. Znów małe obejście – można nadpisać właściwość Items, konkretyzując typ na jakim ma operować:

type
  TEntries = class(spezialize TFPGObjectList<TEntry>)
  public
    property Items[AIndex: Integer]: TEntry read Get write Put; default;
  end;

Na szczęście można skorzystać z istniejących metod pełniących rolę akcesora i mutatora, czyli metod Get i Put, a całość ustawić jako właściwość domyślną, całkowicie przykrywając poprzedniczkę. Plus jest też taki, że w okienku do kompletowania kodu będzie sugerowało naszą (skonkretyzowaną) właściwość Items, a do tej bazowej nie będzie dawać dostępu.

Nazwa takiej właściwości może być inna – nie musi to być akurat Items.


No, w tym momencie da się mieć własną listę generyczną, da się utworzyć jej instancję, kod będzie się kompilował i kompletowanie kodu nie będzie się dławić. Mam nadzieję, że w przyszłości coś się w tej materii zmieni, bo nie jest to zbyt wygodne w obsłudze. Już za kilka tygodni opublikowana zostanie wersja 1.8 środowiska – zobaczymy co nowego się pojawi.

#free-pascal #lazarus

vpiotr

@furious programming: W Delphi 7 robiło się generyki przez $I i nie narzekałem :) A tu masz to opisane - w jednym krótkim kawałku kodu: http://wiki.freepascal.org/Generics

furious programming

@i486: masz z tym jakiś problem?

@kAzek: to pisze ktoś, kto niedawno wrócił z bana za wyzywanie ludzi od „miernot”.

@vpiotr: znam ten artykuł, czytałem ich wiele na ten temat. Generyków używam, choć nie mam do nich przekonania, ze względu na wymienione kombinacje i trochę bugów w środowisku. Zwróć też uwagę na to, że ten artykuł nie wyjaśnia mojego jedynego pytania z tego wpisu (jak utworzyć listę generyczną, nie deklarując wcześniej konkretnego typu danych). Delphi w temacie generyków jest znacznie lepsze. :]

jarekr000000
2017-09-19 18:27

Na scalaworld Aaron Levin pokazał type level routing dla servera http. To kolejny krok po podejsciu funkcyjnym.To daje jednoczesnie testowalnosc podejscia funkcyjnego i łatwe metadane (np swagger) jak w annotacjach. A o po poprawnosc dba kompilator. Mózg r**y.

yarel

Przypomniało mi się jak zobaczyłem XMLa pierwszy raz w życiu. "Po co to komu?" A dziś już wiem ;-) Może kiedyś przyjdzie czas i na "type level routing" ;-)

Pixello

Ja zobaczyłem xml pierwszy raz w życiu i pomyślałem wtf, patrzę na starego csproja i dalej myślę wtf :|

karolinaa
2017-09-19 13:00

#daily_os_monitoring

[LINUX ALERT] NULL
[OS X ALERT] NULL
[WINDOWS ALERT] https://www.wykop.pl/link/392[...]ali-sie-do-programu-ccleaner/

czysteskarpety

u mnie najlepsze efekty dawał Diskeeper+defrag rejestru, na małej partycji na system, reszta (filmy, gry) była nieruszana, potem weszły ssd to wiadomo, szaleństwo i śmiecenie :)

furious programming

Ja używam – codziennie czyszczę dysk tuż przed zamknięciem systemu. Do tego co kilka dni defragmentacja (używam Defragglera, tej samej firmy) i laptop choć leciwy, to działa o wiele szybciej, niż nowe sprzęty ze świeżymi instalacjami systemu – serio. Choć to nie jest jedynie zasługa sprzątania – brak śmieciowych programów (w szczególności producenta komputera) oraz powyłączane zbędne usługi dają sporego kopa.

Mnie problem zainfekowanej wersji nie dotyczy, bo wszędzie mam wyłączone aktualizacje automatyczne – sam sprawdzam i aktualizuję, jeśli się opłaca. CCleaner mam jeszcze w wersji 5.29, więc pełen luzik.

karolinaa
2017-09-19 12:52

Słuchajcie byłam na rozmowie w Facebook'u i dali mi zadanie rozwiązać problem comiwojagera. Nikt mi nie powiedział że to niemożliwe, więc rozwiązałam i jutro mam wywiad z The Science! Trzymajcie kciuki! ;}}}}}}

xfin

@karolinaa: Jakaś normalna informacja pisana na serio, czy znowu narkotyki weszły za mocno? ;) Bo samo rozwiązanie konkretnej instancji problemu jest przecież możliwe. Ten problem po prostu jest NP-hard.

furious programming

@xfin: nażarła się Ketonalu i brzedzi – normalka.

vpiotr
2017-09-19 12:42
vpiotr

@Burdzi0: małymi? Zdajesz sobie sprawę że RaspberryPi to przy Amidze rakieta? A co ludzie robili na Amidze kiedyś... Poza tym w kosmosie do niedawna wykorzystywano 486 (nie wiem jak teraz). W zasadzie to na warunki kosmiczne za dużo prądu pewnie ciągnie. Bardziej bym widział w kosmosie Z-berry. No i pewnie nie jest to główny komputer tylko któryś z wielu pobocznych.

Burdzi0

@vpiotr: Nie interesuję się kosmosem, to nie wiem ;) Nie wiem jak z zasilaniem, ale widzę microUSB, więc pewnie koło 1A, to tyle co RPI 0 W