Z tego co mi sie udalo doczytac a wiekszosc materalow polsko jezycznych
(angielski znam tak slabo ze jak nie wiem o czym czytam to nic nie rozumiem)
tyczy sie dotnetu i visuala
a google na temat typy generyczne + delphi wyrzuca ino pochwaly d2010 dXE ze
tez ma ;)
doczytalem sie wiec ze typy generycnze to taka tablica (lista) gdzie mzona
wepchnac wszstko (wszytskie typy od byte do okiektow i klas) tyle ze nie
kumam po co
Tak sobie kombinuje ze moze chodzi o to aby jedna czesc programu
przekazywala innej czesci (lub innemu programowi w ramach autoamtyzacji) nie
tylko dane ale tez instrukcje co z tymi danymi zrobic.
czyli takie varianty z mozliwoscia przypisania klasy czy procedury.
Zreszta z variantami tak naprawde zatrybilem o co chodzi gdy zobaczylem jak
program przekazuje parametry do FastReporta i teraz tak sobie kombinuje ze
moze za pomoca generykow do takiego fast reporta
mozna by przekazac nie tylko wartosci zmiennych do wyswietlenia ale tez
informacje (klase dla skryptu, formule dla pola wyliczenwego) jak obrobic
dane w innych polach wydruku. Ale moze bredze ;)
wojtek
> moze mi ktos tak lopatologicznie wytlumaczyc o co chodzi z tymi calymi
> typami generycznymi?
> grzebie po googlach ale mam problemy zeby zatrybic (tak jak mialem problemy
> z obiektowoscia przy przechodzeniu z TP na delphi) nie tyle co to jet a po
> co to jest.
A to czytałeś? Do C#, ale z pierwszej strony można już sobie jakieś
intuicje o generykach wyrobić.
http://www.centrumxp.pl/dotNet/715,1,17_Typy_generyczne_generics.aspx
--
PaSkol
>> grzebie po googlach
W sumie wpisując do google: typy generyczne
dostaje się pokaźną ilość stron po polsku.
--
PaSkol
nie... możesz wepchnąć tylko jeden typ. Tyle nieznany w momencie pisanie
kodu dla listy generycznej. Włąściwy kowd wykonywalny zostanie potem
wygenerowany na podstawie kodu listy, i typu którym się skonkretyzuje listę.
dla przykładu, jak masz typ generyczny TList<T>,
to potem łatwo możesz uzysakć:
* lista kontrolek: TList<TControl> - będzie przechowywać tylko kontrolki
* list pól: TList<TField>
* lista datasetów : TList<TDataSet>
* lista wskaźników: TList<Pointer>
> Tak sobie kombinuje ze moze chodzi o to aby jedna czesc programu
> przekazywala innej czesci (lub innemu programowi w ramach autoamtyzacji) nie
> tylko dane ale tez instrukcje co z tymi danymi zrobic.
> czyli takie varianty z mozliwoscia przypisania klasy czy procedury.
Kombinujesz, jak koń pod górkę ;-)
> Zreszta z variantami tak naprawde zatrybilem o co chodzi gdy zobaczylem jak
> program przekazuje parametry do FastReporta i teraz tak sobie kombinuje ze
> moze za pomoca generykow do takiego fast reporta
Nie. Variant przechowywać może wiele różnych typów, w tym tablicę
Variantów.
Generyk tylko jeden typ, tyle że nie sprecyzowany. Typ doprecyzowuje się
w momencie konkretyzacji generyka.
Generyki to jeden ze sposobów na metaprogramowanie. Raz piszesz kod,
używasz wielokrotnie dla różnych typów.
BTW, Generyki w Delphi to pikuś. Zobaczył być co się są zrobić z ich
pierwowzorem, czyli wzorcami (templates) w C++... cudeńka. Dość
powiedzieć, ze standardowy typ stringa w C++ (std::string) jest właśnie
konkretyzacją wzorca std::basic_string<charT, traits, Alloc>, gdzie
typem konkretyzującym jest "char" i jego trait.
Jak w C++ chcesz uzyskać dowolny inny typ stringa (unikodowy, UTF-8,
BCD, 7-bit czy inny), to po prostu konkretyzujesz sobie
std::basic_string<> innym typem znaku. Zero kodowania.
--
Arivald
Może zacznijmy inaczej: jest "od zawsze" w Pascalu tablica. Tablica jest
zawsze "czegoś", np. array of integer.
Teraz w generykach chodzi, aby móc samemu zadeklarować "typ czegoś". Szkoda,
że zastosowano składnię C++. Bardziej naturalnie wyglądałoby
TList of pointer
zamiast
TList<pointer>
Samo TList<T> nie daje zbyt wiele ponad tablicę dynamiczną - ale jest też
TQueue (kolejka), TStack (stos), i ciekawy typ TDictionary (tablica
asocjacyjna).
Słowem: gdy napiszemy swój własny super-magiczny czy wydajny kontener
integerów, a zachciało nam się stringów, nie musimy powielać tony kodu
zamieniając wszystkie "integer" na "string", albo stosować półśrodki w
postaci pointerów: możemy mieć natychmiast naszą kolejkę integerów,
stringów, i TButtonów.
--
Azarien
wersja z array of Tcontrol
ac: array of Tcontrol
dodanie elementu:
SetLength(ac, Length(ac) + 1);
ac[Length(ac) - 1] := someControl;
Wady:
* ręczne zarządzanie pamięcią, podatność na błędy.
* Tragiczna (!) wydajność dodawania. Za kazdym razem realokujesz.
można to zmienić, ale wtedy potrzebujesz dodatkowej zmiennej na
przechowywanie ilości zajętych elementów tablicy.
usuwanie dowolnego elementu:
for i := o to Length(ac) - 1 do
if ac[i] = someControl then
begin
//kopiowanie elementów poza usuwanym na miejsce zajmowane przez
usunięty
Move (..., ..., Length(ac) - i); //nie chce mi się teraz myśleć
jakie dokładnie parametry ... ;-)
SetLength(ac, Length(ac) - 1);
//tu ewentuaknie Break; jesli jeseś pewien ze someControl tylko
raz było w tablicy
end;
Wady:
* Jak poprzednio, ręczne zarządzanie pamięcią, podatność na błędy.
* Tragiczna wydajność.
* tablica jest wektorem: zajmuje jeden ciągły fragment pamięci.
W momencie kiedy usuwasz element ze środka to musisz kopiować czasem
spory kawałek pamięci.
-------------------------------------------------------------------------
wersja z TList<TControl>
ac: TList<TControl>;
dodanie elementu:
ac.Add(someControl);
usuwanie dowolnego elementu:
ac.Remove(someControl);
Wad żadnych nie widzę.
Dodatkowo, implementacja TList to może nie być wektor, a np linked-list,
czy hash-table, co ma ogromy wpływ na wydajność.
Przy dobrze zaprojektowanej rodzinie kontenerów (TVector<T>, TQueue<T>,
TStack<T>, THashTable<T>, TLinkedList<T>, etc) kontenery są wymienne
(mają spójne API), i można łatwo przetestować wpływ konkretnej
implementacji kontenera na wydajność w danym algorytmie.
--
Arivald
nie? przynajmniej z analizy kodu Free Pascala kiedyś wynikło mi że nie.
Chyba że Delphi jest gorsze pod tym względem...
--
Azarien
Czyli za pomocą deklaracji TList<TControl> uzyskujemy listę której
elementami są obiekty TControl?
A można to zapisać jako var a: TList; jako elementy dodawane do listy
wskaźniki do innych obiektów?
> Słowem: gdy napiszemy swój własny super-magiczny czy wydajny kontener
> integerów, a zachciało nam się stringów, nie musimy powielać tony kodu
> zamieniając wszystkie "integer" na "string", albo stosować półśrodki w
> postaci pointerów: możemy mieć natychmiast naszą kolejkę integerów,
> stringów, i TButtonów.
Zamiast pisać, lepiej korzystać ;-)
http://code.google.com/p/delphilhlplib/wiki/FeatureList
I koniecznie zapoznać się co to jest ENEX w konwencji DeHL'a, a daje coś
takiego "Enex (Enumerable Extensions) provide Linq-like possibilities
for all DeHL collections."
Gdzie słowo-klucz to "Linq-like", co to daje?
Rzut oka na IEnexCollection<T>, gdzie można znaleźć takie metody:
function Aggregate : IEnexCollection<T>;
function Max : IEnexCollection<T>;
function Min : IEnexCollection<T>;
function Ordered : IEnexCollection<T>;
function Ordered : IEnexCollection<T>;
function Range : IEnexCollection<T>;
function Reversed : IEnexCollection<T>;
function SkipWhile : IEnexCollection<T>;
function SkipWhileBetween : IEnexCollection<T>;
function SkipWhileGreater : IEnexCollection<T>;
function SkipWhileGreaterOrEqual : IEnexCollection<T>;
function SkipWhileLower : IEnexCollection<T>;
function SkipWhileLowerOrEqual : IEnexCollection<T>;
function Union : IEnexCollection<T>;
function Where : IEnexCollection<T>;
function WhereBetween : IEnexCollection<T>;
function WhereGreater : IEnexCollection<T>;
function WhereGreaterOrEqual : IEnexCollection<T>;
function WhereLower : IEnexCollection<T>;
function WhereLowerOrEqual : IEnexCollection<T>;
function WhereNot : IEnexCollection<T>;
Proszę zwrócić uwagę, że każda metoda zwraca referencję własnego
interfejsu (tzw builder, szczegóły np. w TStringBuilder), a więc można
napisać coś takiego:
MaxValue := collection.
Where(coś tam).
Max(coś tam);
--
wloochacz
> Czyli za pomocą deklaracji TList<TControl> uzyskujemy listę której
> elementami są obiekty TControl?
Tak.
> A można to zapisać jako var a: TList; jako elementy dodawane do listy
> wskaźniki do innych obiektów?
Deklarując zmienną typu generycznego, robisz tzw. konkretyzację - a więc
wskazujesz jakim type ma się owa konkretna instancja typu generycznego
(tu: TList<T>) posługiwać.
Możesz tam wpisać cokolwiek:
TList<Pointer> - wskaźniki na cokolwiek
TList<TObject> - referencje dowolnych obiektów
--
wloochacz
Dostajesz silną kontrolę typów bez pisania tych samych algorytmów dla
różnych struktur danych.
np jeżeli tlf = tList<TField>, ds=tDataSet
to kompilator nie puści
tlf.add(ds);
obecnie albo dopuszczasz każdy obiekt, albo piszesz odrębne implementacje
--
Darek
Tak. Plus kontrolę typu elementu w trakcie kompilacji.
> A można to zapisać jako var a: TList; jako elementy dodawane do listy
> wskaźniki do innych obiektów?
>
a: TList przechowuje wskaźniki. Możesz tam dodać obiekty, ale przy
wyciąganiu nie masz gwarancji ze wskaźnik który wyciągniesz jest
obiektem, czy TControl w szczególności.
Przy TList<TControl> masz gwarancję że lista przyjmie tylko pochodne
TControl, a kompilator Cię ostrzeże jeśli spróbujesz tam przypisać coś
innego. To upraszcza wiele kodu.
Z drugiej strony, przy TList<integer> masz pewność ze w liście są tylko
liczby, a TList<string> przechowuje stringi.
--
Arivald
właśnie: liczby, a nie wskaźniki na te liczby. odpada zbędna alokacja tego,
co może być w miejscu.
--
Azarien
właśnie: mogą być liczby, a nie wskaźniki na te liczby. odpada zbędna
alokacja tego,
co może być w miejscu.
No, chyba że TList jest skopane pod tym względem. Byłoby szkoda. Jak jest
naprawdę: czy TList<integer> wewnętrznie przechowuje integery czy wskaźniki?
--
Azarien
jakieś szczegóły?
> MaxValue := collection.
> Where(coś tam).
> Max(coś tam);
Aaale fajne... tylko dokumentacja do tego dehla jest tragiczna wręcz.
--
Azarien
Właśnie przekonałeś mnie do upgrade-u Delphi
Tomek D.
> Właśnie przekonałeś mnie do upgrade-u Delphi
Uważaj; D2010 ma problemy z zagnieżdżonymi typami generycznymi (nie da
się używać tego typu, poza modułem w którym został zadeklarowany -
internal error urw:111 - full wypas normalnie...)
D2009 w ogóle się nie da na poważnie z generyków korzystać.
Podobno (podobno, bo sam nie wiem i wolę aby inni byli beta testerami)
Delphi XE rozwiązuje w/w problemy.
--
wloochacz
>> MaxValue := collection.
>> Where(coś tam).
>> Max(coś tam);
>
>
> Aaale fajne... tylko dokumentacja do tego dehla jest tragiczna wręcz.
Nie wiesz jak się z list kontenerów korzysta?
Tak jak sobie wymyślisz ;-)
Powiadasz, że dokumentacja jest tragiczna?
Zanim coś powiesz, zajrzyj do źródeł; WSZYSTKO jest opisane w
komentarzach do każdej metody.
Poza tym, to jest bardzo dobry kod za free - odrobina pokory.
--
wloochacz
Nie wiem dokładnie, co tam jest. Albo co w którym unicie.
Oczywiście - są źródła. Szkoda że nie zastosowali jakiegoś systemu do
generowania dokumentacji.
--
Azarien