🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: pl.comp.lang.delphi
Article #334825

Re: E2032 For loop control variable must have ordinal type

#334825
From: jh
Date: Tue, 17 Jan 2012 09:45
115 lines
5547 bytes
W dniu 16.01.2012 23:57, wloochacz pisze:

> A tak:
> sl := TSingleList.(TSingleList.CreateList('Single List', -1));
> I dlaczego się kompiluje?
> No więc właśnie...

OK (wiadomo, bez kropki przed nawiasem). Tylko trochę to pokrętne, bo:

type
   TCustomList<T> = class(TObjectDictionary<Integer, T>)
   private
     FListID: Integer;
     FListName: string;
   public
     class function CreateList(const AListName: String;
             const AListID: Integer = -1): TCustomList<T>;

     property ListName: string read FListName write FListName;
     property ListID: Integer read FListID write FListID;
   end;

   TSingleList = class(TCustomList<string>)
   public
   end;

var
   sl: TSingleList;
   s: string;

   sl := TSingleList(TSingleList.CreateList('Single List', -1));
   try
     if (sl is TCustomList<string>) then
      s := 'sl IS TCustomList<string>, '
     else
       s := 'sl IS NOT TCustomList<string>, ';
     if (sl is TSingleList) then
      s := s + 'and IS TSingleList, its ClassName is ' + sl.ClassName
     else
       s := s + 'and IS NOT TSingleList, its ClassName is ' + sl.ClassName;
   finally
     sl.Free;
   end;


s zwraca:

sl IS TCustomList<string>, and IS TSingleList, its ClassName is 
TCustomList<System.string>

Same generyki w wersji Delphi zrozumiałem tak:
Kod - zapis - jest w momencie kompilacji generowany na podstawie 
szablonu, po podstawieniu w miejsce placeholderów właściwych typów. 
Czyli, kompilator dostaje już kod na zasadzie search&replace <T> na 
<nazwa typu>. Jeżeli teraz posługuję się dziedziczeniem takiej 
generycznej definicji, to zrozumiałem to tak, że (obrazowo) mam kolejne 
wersje kodu z dopisaną funkcjonalnością, które już (podając konkretny 
typ) same dokonują owego search&replace, wprowadzają nowe placeholdery i 
finalnie kompilator dostaje taki scalony kod klasy, która z nazwami tych 
nadrzędnych generycznych klas nie ma nic wspólnego. Zatem w moim 
przykładzie TCustomList<string> jest zupełnie inną klasą niż 
TSingleList, choć powstały na bazie tego samego zapisu.

[Po 5 minutach :D]
Przeczytałem powyższe i chyba zrozumiałem, gdzie popełniam błąd. Powinno 
być tak, że oprócz tej mojej docelowej klasy (TSingleList) powstają 
również TCustomList<string>, TObjectDictionary<Integer, string>, 
TDictionary<Integer, String> itd. Czyli na podstawie podawanych 
konkretnych typów - podczas dziedziczenia, również tworzony są klasy 
nadrzędne z tymi właśnie typami. Zatem powstaje nie tyle finalna - 
"scalona" wersja klasy, ale te klasy nadrzędne - podobnie jak to ma 
miejsce w tradycyjnym dziedziczeniu. Takie "na chłopski rozum" 
tłumaczenie, chyba jest sensowne w kontekście powyższej wartości owego 
"s". Tam konstruktor był w TCustomList<T> i stąd zwrócona taka nazwa 
klasy obiektu TSingleList, choć posiada on metody i pola dostępne 
dopiero od klasy TSingleList, a które nie zostały jeszcze wprowadzone w 
TCustomList<T>.


> Nie wiem dlaczego, ale próbujesz na siłę wykorzystać typy generyczne aby
> robiły za polimorfizm.
> Po co tak?

To tylko w ramach nauki. Dotąd robiłem tradycyjnie, bez typów 
generycznych. Liczyłem na pominięcie tego rzutowania, które miałem w 
listach zbudowanych z np. TObjectList czy TList.


> To co chcesz uzyskać, to się da i robi, tyle że bez typów generycznych
> za to z typami klasowymi.
> Zerknij np. na to:
> http://docwiki.embarcadero.com/Libraries/en/Vcl.ComCtrls.TCustomTreeView.OnCreateNodeClass
>
> Jak widzisz w tym zdarzeniu możesz do TTreeView przekazać dowolną klasę
> (która dziedziczy z TTreeNode) aby Node (liść, węzeł), który zostanie
> utworzony był instancją klasy którą przekażesz w tym zdarzeniu.

OK, to jest zrozumiałe. Tylko zamotałem się z tym dziedziczeniem 
generyków. To powyższe (OnCreateNodeClass) można nazwać fabryką klas 
dziedziczących z TTreeNode?


> Spójrz jak rozwiązano np. sortowanie w TList<T> (aczkolwiek to nieco
> zakręcony przykład) ale co ważniejsze, dlaczego sam algorytm sortowania
> został oddelegowany na zewnątrz i nie jest w żaden sposób
> zaimplementowany w TList<T>?
> Jakbyś zaimplementował sortowanie elementów listy dla ogólnego typu
> (czyli <T>), bo przecież na pewni nie wewnątrz klasy TList<T>, prawda?

No właśnie dotarłem w lekturze do metod anonimowych i jest mowa o 
sortowaniu TList<T> :P

Dzięki za wskazówki.

jh
Technical Details
Message-ID: <jf3g0d$iq1$1@inews.gazeta.pl>
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.gazeta.pl!not-for-mail
References: <jf1eso$r2g$1@inews.gazeta.pl> <jf1hvq$6dj$1@inews.gazeta.pl> <15e8um5ehdue7.dlg@hell.heaven> <jf27m9$is9$1@inews.gazeta.pl> <jf2a0j$qcl$1@inews.gazeta.pl>

Show Full Headers
Complete Article Headers
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.gazeta.pl!not-for-mail
From: jh <no-email@sorry.com>
Newsgroups: pl.comp.lang.delphi
Subject: Re: E2032 For loop control variable must have ordinal type
Date: Tue, 17 Jan 2012 10:45:49 +0100
Organization: "Portal Gazeta.pl -> http://www.gazeta.pl"
Lines: 116
Message-ID: <jf3g0d$iq1$1@inews.gazeta.pl>
References: <jf1eso$r2g$1@inews.gazeta.pl> <jf1hvq$6dj$1@inews.gazeta.pl> <15e8um5ehdue7.dlg@hell.heaven> <jf27m9$is9$1@inews.gazeta.pl> <jf2a0j$qcl$1@inews.gazeta.pl>
NNTP-Posting-Host: rk-193-19-124-170.kielce.net.pl
Mime-Version: 1.0
X-Trace: inews.gazeta.pl 1326793551 19265 193.19.124.170 (17 Jan 2012 09:45:51 GMT)
X-Complaints-To: usenet@agora.pl
NNTP-Posting-Date: Tue, 17 Jan 2012 09:45:51 +0000 (UTC)
X-User: jh0909nowe
In-Reply-To: <jf2a0j$qcl$1@inews.gazeta.pl>
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:9.0) Gecko/20111222 Thunderbird/9.0.1
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit