* * *

Author Topic: Generic Generic list  (Read 3233 times)

Edson

  • Hero Member
  • *****
  • Posts: 806
Generic Generic list
« on: February 24, 2017, 09:19:44 pm »
I have this:
Code: Pascal  [Select]
  1.  
  2.   TA = class ...
  3.  
  4.   TA1 = class(TA) ...
  5.   TA1_list = specialize TFPGObjectList<TA1>;  
  6.  
  7.   TA2 = class(TA) ...
  8.   TA2_list = specialize TFPGObjectList<TA2>;  
  9.  
  10.    list1: TA1_list;
  11.    list2: TA2_list
  12.  

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]
  1.   TA_list = specialize TFPGObjectList<TA>;  
  2.   list: TA_list;
  3.   list := TA_list(list1);   //WARNING: class types not related
  4.   for item in list do ...
  5.  

This seems to work, but looks some weird  %)
I'm sure there are better ways. Suggestions?
Lazarus 1.6 - FPC 3.0.0 - x86_64-win64 on  Windows 7

ASerge

  • Sr. Member
  • ****
  • Posts: 477
Re: Generic Generic list
« Reply #1 on: February 25, 2017, 02:40:16 pm »
How about that:
Code: Pascal  [Select]
  1. for item in list1 do ...; for item in list2 do ...;

Edson

  • Hero Member
  • *****
  • Posts: 806
Re: Generic Generic list
« Reply #2 on: February 25, 2017, 04:28:43 pm »
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]
  1.   TA_list = specialize TFPGObjectList<TA>;  
  2.   list: TA_list;
  3.   list := TA_list(list1);   //WARNING: class types not related
  4.   for item in list do ...

is working, but I have the feeling, this is not the best way to face the problem.
Lazarus 1.6 - FPC 3.0.0 - x86_64-win64 on  Windows 7

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 5875
Re: Generic Generic list
« Reply #3 on: February 25, 2017, 04:41:22 pm »
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

  • Hero Member
  • *****
  • Posts: 806
Re: Generic Generic list
« Reply #4 on: February 25, 2017, 05:34:30 pm »
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.
Lazarus 1.6 - FPC 3.0.0 - x86_64-win64 on  Windows 7

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 5875
Re: Generic Generic list
« Reply #5 on: February 25, 2017, 08:28:16 pm »
Of course when you go to a non-native backend (LLVM,JVM) then all bets are off.

Thaddy

  • Hero Member
  • *****
  • Posts: 4807
Re: Generic Generic list
« Reply #6 on: February 25, 2017, 08:41:34 pm »
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]
  1. for item<T> in list<T> do..
I know it doesn't work..yet.
« Last Edit: February 25, 2017, 08:49:19 pm by Thaddy »
"Logically, no number of positive outcomes at the level of experimental testing can confirm a scientific theory, but a single counterexample is logically decisive."

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 5875
Re: Generic Generic list
« Reply #7 on: February 25, 2017, 08:55:17 pm »
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).

(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

  • Sr. Member
  • ****
  • Posts: 477
Re: Generic Generic list
« Reply #8 on: February 25, 2017, 11:26:56 pm »
It 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

  • Hero Member
  • *****
  • Posts: 806
Re: Generic Generic list
« Reply #9 on: February 26, 2017, 03:17:44 am »
Do 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.
Lazarus 1.6 - FPC 3.0.0 - x86_64-win64 on  Windows 7

ASerge

  • Sr. Member
  • ****
  • Posts: 477
Re: Generic Generic list
« Reply #10 on: February 26, 2017, 08:05:22 pm »
Well, if there are many types of lists, it may be a lot of procedures?
Code: Pascal  [Select]
  1. {$APPTYPE CONSOLE}
  2. program Project1;
  3.  
  4. uses fgl;
  5.  
  6. type
  7.   TA = class(TObject)
  8.     procedure Print;
  9.   end;
  10.  
  11.   TA1 = class(TA);
  12.   TA2 = class(TA);
  13.  
  14.   generic TGMyListWithProc<T: TA> = class(TObject)
  15.   public
  16.     type
  17.       TList = specialize TFPGObjectList<T>;
  18.     class procedure ForEachPrint(List: TList); static;
  19.   end;
  20.  
  21.   TMyList1 = specialize TGMyListWithProc<TA1>;
  22.   TMyList2 = specialize TGMyListWithProc<TA2>;
  23.  
  24. procedure TA.Print;
  25. begin
  26.   Writeln(ClassName);
  27. end;
  28.  
  29. class procedure TGMyListWithProc.ForEachPrint(List: TList);
  30. var
  31.   Item: T;
  32. begin
  33.   for Item in List do
  34.     Item.Print;
  35. end;
  36.  
  37. var
  38.   List1: TMyList1.TList;
  39.   List2: TMyList2.TList;
  40. begin
  41.   List1 := TMyList1.TList.Create;
  42.   try
  43.     List1.Add(TA1.Create);
  44.     TMyList1.ForEachPrint(List1);
  45.   finally
  46.     List1.Free;
  47.   end;
  48.   List2 := TMyList2.TList.Create;
  49.   try
  50.     List2.Add(TA2.Create);
  51.     TMyList2.ForEachPrint(List2);
  52.   finally
  53.     List2.Free;
  54.   end;
  55.   ReadLn;
  56. end.

Edson

  • Hero Member
  • *****
  • Posts: 806
Re: Generic Generic list
« Reply #11 on: March 01, 2017, 04:22:14 pm »
Thanks @ASerge.

Well, if there are many types of lists, it may be a lot of procedures?
Code: Pascal  [Select]
  1. {$APPTYPE CONSOLE}
  2. program Project1;
  3.  
  4. uses fgl;
  5.  
  6. type
  7.   TA = class(TObject)
  8.     procedure Print;
  9.   end;
  10.  
  11.   TA1 = class(TA);
  12.   TA2 = class(TA);
  13.  
  14.   generic TGMyListWithProc<T: TA> = class(TObject)
  15.   public
  16.     type
  17.       TList = specialize TFPGObjectList<T>;
  18.     class procedure ForEachPrint(List: TList); static;
  19.   end;
  20.  
  21.   TMyList1 = specialize TGMyListWithProc<TA1>;
  22.   TMyList2 = specialize TGMyListWithProc<TA2>;
  23.  
  24. procedure TA.Print;
  25. begin
  26.   Writeln(ClassName);
  27. end;
  28.  
  29. class procedure TGMyListWithProc.ForEachPrint(List: TList);
  30. var
  31.   Item: T;
  32. begin
  33.   for Item in List do
  34.     Item.Print;
  35. end;
  36.  
  37. var
  38.   List1: TMyList1.TList;
  39.   List2: TMyList2.TList;
  40. begin
  41.   List1 := TMyList1.TList.Create;
  42.   try
  43.     List1.Add(TA1.Create);
  44.     TMyList1.ForEachPrint(List1);
  45.   finally
  46.     List1.Free;
  47.   end;
  48.   List2 := TMyList2.TList.Create;
  49.   try
  50.     List2.Add(TA2.Create);
  51.     TMyList2.ForEachPrint(List2);
  52.   finally
  53.     List2.Free;
  54.   end;
  55.   ReadLn;
  56. 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]
  1. program Project1;
  2. uses fgl;
  3. type
  4.   TA = class(TObject)
  5.     procedure Print;
  6.   end;
  7.  
  8.   TA1 = class(TA);
  9.   TA2 = class(TA);
  10.  
  11.   TMyList1 = specialize TFPGObjectList<TA1>;
  12.   TMyList2 = specialize TFPGObjectList<TA2>;
  13.  
  14.   TMyList = specialize TFPGObjectList<TA>;
  15.  
  16. procedure DoSomethingWithAnyList(list: TMyList);
  17. var Item: TA;
  18. begin
  19.   for Item in List do
  20.     Item.Print;
  21. end;
  22.  
  23. procedure TA.Print;
  24. begin
  25.   Writeln(ClassName);
  26. end;
  27.  
  28. var
  29.   List1: TMyList1;
  30.   List2: TMyList2;
  31. begin
  32.   List1 := TMyList1.Create;
  33.   List1.Add(TA1.Create);
  34.  
  35.   List2 := TMyList2.Create;
  36.   List2.Add(TA2.Create);
  37.  
  38.   DoSomethingWithAnyList(TMyList(List1));  //Warning
  39.   DoSomethingWithAnyList(TMyList(List2));  //Warning
  40.  
  41.   ReadLn;
  42. end.

Something like this, but without warnings  :o.

Lazarus 1.6 - FPC 3.0.0 - x86_64-win64 on  Windows 7

Thaddy

  • Hero Member
  • *****
  • Posts: 4807
Re: Generic Generic list
« Reply #12 on: March 01, 2017, 04:33:49 pm »
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...
« Last Edit: March 01, 2017, 04:38:50 pm by Thaddy »
"Logically, no number of positive outcomes at the level of experimental testing can confirm a scientific theory, but a single counterexample is logically decisive."

Edson

  • Hero Member
  • *****
  • Posts: 806
Re: Generic Generic list
« Reply #13 on: March 02, 2017, 05:15:02 pm »
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.   :)
Lazarus 1.6 - FPC 3.0.0 - x86_64-win64 on  Windows 7

 

Recent

Get Lazarus at SourceForge.net. Fast, secure and Free Open Source software downloads Open Hub project report for Lazarus