Generic Generic list lazarus / 62-General ---------------------------------------------------------------------- Edson · 2017-02-24 20:19 I have this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i    TA = class ...   TA1 = class(TA) ...  TA1_list = specialize TFPGObjectList;      TA2 = class(TA) ...  TA2_list = specialize TFPGObjectList;       list1: TA1_list;   list2: TA2_list list1 and list2 are filled with items; Then I need to iterate through list1 or list2, to access methods of TA. I have done this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   TA_list = specialize TFPGObjectList;     list: TA_list;  list := TA_list(list1);   //WARNING: class types not related  for item in list do ...  This seems to work, but looks some weird  I'm sure there are better ways. Suggestions? ---------------------------------------------------------------------- ASerge · 2017-02-25 13:40 How about that: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i for item in list1 do ...; for item in list2 do ...; ---------------------------------------------------------------------- Edson · 2017-02-25 15:28 It would be easy, but there are more than two list. And the quantity will be increasing. I need some kind of ancestor for all this generic list, to use for a general iteration. Until now, my solution: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   TA_list = specialize TFPGObjectList;    list: TA_list;  list := TA_list(list1);   //WARNING: class types not related  for item in list do ... is working, but I have the feeling, this is not the best way to face the problem. ---------------------------------------------------------------------- marcov · 2017-02-25 15:41 I have also encountered similar problems in Delphi, and used a typecast, which always went fine. Usually to pass an array of a descendent type to a method that accepted an array of the parent type. It is not entirely typesafe, but IMHO the risk is fairly low since the size of elements and everything are the same. So basically the only difference is the type reference in whatever the dynamic array descriptor is. ---------------------------------------------------------------------- Edson · 2017-02-25 16:34 Thanks @markov That's what I wanted to hear. I think it's not typesafe, too, but it works well. I will be implementing this method in my design, unless I see there are collateral effects. ---------------------------------------------------------------------- marcov · 2017-02-25 19:28 Of course when you go to a non-native backend (LLVM,JVM) then all bets are off. ---------------------------------------------------------------------- Thaddy · 2017-02-25 19:41 Hmm. That's a bit of nonsense since there are jvm native processors for a very, very long time. (mainly smart cards. jvm implemented in hardware. E.g. Gemplus https://en.wikipedia.org/wiki/Java_Card). Anyway. My gut feeling says this could be massaged into something like: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i for item in list do.. I know it doesn't work..yet. ---------------------------------------------------------------------- marcov · 2017-02-25 19:55 Quote from: Thaddy on February 25, 2017, 08:41:34 pmHmm. That's a bit of nonsense since there are jvm native processors for a very, very long time. (mainly smart cards. jvm implemented in hardware. E.g. Gemplus https://en.wikipedia.org/wiki/Java_Card). (LLVM is also not the native backend, yet can generate native code, you seem to confuse native backend (as in FPC's backend) with native code) The point is that the type system of such systems is potentially totally different, making the cast dangerous or invalid ---------------------------------------------------------------------- ASerge · 2017-02-25 22:26 Quote from: Edson on February 25, 2017, 04:28:43 pmIt would be easy, but there are more than two list. And the quantity will be increasing. Do you really need TA_list1, TA_list2, ...? TA_list can hold any TA1, TA2, ... instances. ---------------------------------------------------------------------- Edson · 2017-02-26 02:17 Quote from: ASerge on February 25, 2017, 11:26:56 pmDo you really need TA_list1, TA_list2, ...? TA_list can hold any TA1, TA2, ... instances. Yes, I know TA_list can hold TA1, TA2, ... However, I have differentes objects, each one with its own list ( TA1_list, TA2_list, ...) and I need to pass all this lists, like parameters of a method. ---------------------------------------------------------------------- ASerge · 2017-02-26 19:05 Well, if there are many types of lists, it may be a lot of procedures? Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$APPTYPE CONSOLE}program Project1; uses fgl; type  TA = class(TObject)    procedure Print;  end;   TA1 = class(TA);  TA2 = class(TA);   generic TGMyListWithProc = class(TObject)  public    type      TList = specialize TFPGObjectList;    class procedure ForEachPrint(List: TList); static;  end;   TMyList1 = specialize TGMyListWithProc;  TMyList2 = specialize TGMyListWithProc; procedure TA.Print;begin  Writeln(ClassName);end; class procedure TGMyListWithProc.ForEachPrint(List: TList);var  Item: T;begin  for Item in List do    Item.Print;end; var  List1: TMyList1.TList;  List2: TMyList2.TList;begin  List1 := TMyList1.TList.Create;  try    List1.Add(TA1.Create);    TMyList1.ForEachPrint(List1);  finally    List1.Free;  end;  List2 := TMyList2.TList.Create;  try    List2.Add(TA2.Create);    TMyList2.ForEachPrint(List2);  finally    List2.Free;  end;  ReadLn;end. ---------------------------------------------------------------------- Edson · 2017-03-01 15:22 Thanks @ASerge. Quote from: ASerge on February 26, 2017, 08:05:22 pmWell, if there are many types of lists, it may be a lot of procedures? Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$APPTYPE CONSOLE}program Project1; uses fgl; type  TA = class(TObject)    procedure Print;  end;   TA1 = class(TA);  TA2 = class(TA);   generic TGMyListWithProc = class(TObject)  public    type      TList = specialize TFPGObjectList;    class procedure ForEachPrint(List: TList); static;  end;   TMyList1 = specialize TGMyListWithProc;  TMyList2 = specialize TGMyListWithProc; procedure TA.Print;begin  Writeln(ClassName);end; class procedure TGMyListWithProc.ForEachPrint(List: TList);var  Item: T;begin  for Item in List do    Item.Print;end; var  List1: TMyList1.TList;  List2: TMyList2.TList;begin  List1 := TMyList1.TList.Create;  try    List1.Add(TA1.Create);    TMyList1.ForEachPrint(List1);  finally    List1.Free;  end;  List2 := TMyList2.TList.Create;  try    List2.Add(TA2.Create);    TMyList2.ForEachPrint(List2);  finally    List2.Free;  end;  ReadLn;end. What I see this is creating two different classes and two different iteration code (although reusing the code  ). I was thinking on using just one routine (will be part of a class), that can accept different generic list: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program Project1;uses fgl;type  TA = class(TObject)    procedure Print;  end;   TA1 = class(TA);  TA2 = class(TA);   TMyList1 = specialize TFPGObjectList;  TMyList2 = specialize TFPGObjectList;   TMyList = specialize TFPGObjectList; procedure DoSomethingWithAnyList(list: TMyList);var Item: TA;begin  for Item in List do    Item.Print;end; procedure TA.Print;begin  Writeln(ClassName);end; var  List1: TMyList1;  List2: TMyList2;begin  List1 := TMyList1.Create;  List1.Add(TA1.Create);   List2 := TMyList2.Create;  List2.Add(TA2.Create);   DoSomethingWithAnyList(TMyList(List1));  //Warning  DoSomethingWithAnyList(TMyList(List2));  //Warning   ReadLn;end. Something like this, but without warnings  . ---------------------------------------------------------------------- Thaddy · 2017-03-01 15:33 As long as you try to hard cast..... " DoSomethingWithAnyList(TMyList(List1));  //Warning" How can the compiler tell anything else than a warning?..... Actually that is already more than I expected. What the compiler says to you is: "I know you are probably stupid... I do what you want... but... if I do it wrong it is your fault." A hard cast bypasses the type checks.... Listen to what the compiler says... ---------------------------------------------------------------------- Edson · 2017-03-02 16:15 Well, I don`t complaint about the compiler message. It is very useful. I just was asking if there is some other way for solve this problem (a way to process many generic lists), without disturbing the compiler. ---------------------------------------------------------------------- flowCRANE · 2019-02-01 23:10 Forgive me for digging up the thread, but I had the same problem and solved it in a fairly simple way. We have a base type that has universal data for all inheriting classes, for example: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i type  TThing = class(TObject)  private    FName: String;  public    constructor Create(); virtual; abstract;  public    property Name: String read FName;  end; and the type of a generic list of such objects: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i type  TThings = specialize TFPGObjectList; They inherit two classes from the base class, for example: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i type  TSmallThing = class(TThing)  public    constructor Create(); override; // determines the value of the FName field  end; type  TBigThing = class(TThing)  public    constructor Create(); override; // determines the value of the FName field  end; Each of them has a dedicated type of generic list, because it is required: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i type  TSmallThings = specialize TFPGObjectList;  TBigThings   = specialize TFPGObjectList; Now we need a routine, which has in the parameter to retrieve any list containing objects inheriting from the base class (TSmallThings or TBigThings) and which only operates on data from the base class (here: uses the Name property). If we declare a parameter as a list with objects of the base class: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure ShowThingNames(AThings: TThings);var  Thing: TThing;begin  for Thing in AThings do    WriteLn(Thing.Name);   WriteLn();end; and we will provide a list of the type containing end-class objects, a compilation error related to type mismatches will occur:: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var  SmallThings: TSmallThings;begin  SmallThings := TSmallThings.Create();  ShowThingNames(SmallThings); // Error: Incompatible type To be able to compile the code, we can use casting (it will work properly), but we will get a warning: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var  SmallThings: TSmallThings;begin  SmallThings := TSmallThings.Create();  ShowThingNames(TThings(SmallThings)); // Warning: Class types are not related The simplest solution, which allows to deceive the compiler and not force it to check types (and by the way, to display warnings), is to use the untyped parameters and absolute: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure ShowThingNames(const AThings);var  Things: TThings absolute AThings;  Thing: TThing;begin  for Thing in Things do    WriteLn(Thing.Name);   WriteLn();end; Thanks to this, the code will compile without errors and warnings, and we can pass to the routine a list of any objects inheriting from the base class: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var  SmallThings: TSmallThings;  BigThings: TBigThings;begin  SmallThings := TSmallThings.Create();  BigThings := TBigThings.Create();  try    SmallThings.Add(TSmallThing.Create());    SmallThings.Add(TSmallThing.Create());     BigThings.Add(TBigThing.Create());    BigThings.Add(TBigThing.Create());     ShowThingNames(SmallThings);  ShowThingNames(BigThings);  finally    SmallThings.Free();    BigThings.Free();  end;end. The downside of this solution is the lack of control of the data types provided in the parameter — this is not a safe solution. Therefore, you must use such routines with your head, taking care of correctness on your own. Sources of the test project in the attachment. ---------------------------------------------------------------------- mm7 · 2020-05-30 16:02 Thanks you  furious programming !!!! It helps!