Recent

Author Topic: Missing Assign method in RTL-Generics Classes  (Read 1073 times)

simone

  • Hero Member
  • *****
  • Posts: 573
Missing Assign method in RTL-Generics Classes
« on: August 08, 2022, 03:06:49 pm »
I'm converting an old code base that uses FGL intensively, to replace above library with RTL-Generics. Conversion is not presenting any particular difficulties. However, there is a detail that I noticed and wanted to share.

I've seen that while TFPGObjectList<T> in FGL has the assign method to copy all elements of one list to another, its RTL-generics counterpart TObjectList<T> does not have such a method. It is not a problem to solve this. But I'm curious to know if it is an oversight or a choice dictated by specific reasons.

Thanks in advance.
« Last Edit: August 08, 2022, 03:27:26 pm by simone »
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: Missing Assign method in RTL-Generics Classes
« Reply #1 on: August 08, 2022, 03:12:12 pm »
Seems that Embarcadero chose a different approach for those:

https://stackoverflow.com/questions/9787296/is-there-an-easy-way-to-copy-the-tdictionary-content-into-another.

I assume the ownership properties of objectlist can also complicate this.

Thaddy

  • Hero Member
  • *****
  • Posts: 14204
  • Probably until I exterminate Putin.
Re: Missing Assign method in RTL-Generics Classes
« Reply #2 on: August 08, 2022, 04:02:33 pm »
TFpgObjectList is NOT part of RTL-Generics but part of FGL, that is correct.
The mechanism that Rtl-generics uses is either through its constructors, TEnumerable<T> as common ancestor for collections.
Or you can use its array transfer utility functions.
So assignment is easily possible, it just uses different symantics.
« Last Edit: August 08, 2022, 04:17:06 pm by Thaddy »
Specialize a type, not a var.

simone

  • Hero Member
  • *****
  • Posts: 573
Re: Missing Assign method in RTL-Generics Classes
« Reply #3 on: August 08, 2022, 04:04:45 pm »
I think you don't read before you write (again).

(removed after Thaddy's rectification)
« Last Edit: August 08, 2022, 04:22:53 pm by simone »
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

Thaddy

  • Hero Member
  • *****
  • Posts: 14204
  • Probably until I exterminate Putin.
Re: Missing Assign method in RTL-Generics Classes
« Reply #4 on: August 08, 2022, 04:17:37 pm »
No. If you payed attention the issue was solved. Added explanation of TEnumerable<T>, though.
Specialize a type, not a var.

simone

  • Hero Member
  • *****
  • Posts: 573
Re: Missing Assign method in RTL-Generics Classes
« Reply #5 on: August 08, 2022, 04:19:31 pm »
Thaddy, you accuse me of mixing two frameworks. I have COMPARED, not MIXED.

(removed after Thaddy's rectification)
« Last Edit: August 08, 2022, 04:23:23 pm by simone »
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

simone

  • Hero Member
  • *****
  • Posts: 573
Re: Missing Assign method in RTL-Generics Classes
« Reply #6 on: August 08, 2022, 05:32:24 pm »
TFpgObjectList is NOT part of RTL-Generics but part of FGL, that is correct.
The mechanism that Rtl-generics uses is either through its constructors, TEnumerable<T> as common ancestor for collections.
Or you can use its array transfer utility functions.
So assignment is easily possible, it just uses different symantics.

This explanation is very interesting. If I understand correctly, this approach is similar to C++ copy constructors.

I did an experiment to see if I understood, but something is wrong with my example. List2 is not instantiated, nor is populated
with the values of List1. What am I missing?

Code: Pascal  [Select][+][-]
  1. program Project1;
  2. {$Mode ObjFPC}
  3. uses
  4.   Generics.Collections;
  5. type
  6.  
  7.   { TMyType }
  8.  
  9.   TMyType=class
  10.     Field1 : integer;
  11.     Field2 : integer;
  12.     procedure Write;
  13.     constructor Create(Value1, Value2 : integer);
  14.   end;
  15.  
  16.   TMyList=specialize TObjectList<TMyType>;
  17.  
  18. var
  19.   List1, List2 : TMyList;
  20.   Item : TMyType;
  21.  
  22. { TMyType }
  23.  
  24. procedure TMyType.Write;
  25. begin
  26.   writeln(Field1,'-',Field2);
  27. end;
  28.  
  29. constructor TMyType.Create(Value1, Value2: integer);
  30. begin
  31.   Field1:=Value1;
  32.   Field2:=Value2;
  33. end;
  34.  
  35. begin
  36.   List1:=TMyList.Create;
  37.   List1.Add(TMyType.Create(1,2));
  38.   List1.Add(TMyType.Create(3,4));
  39.   List2.Create(List1);
  40.  
  41.   for Item in List2 do
  42.     Item.Write;
  43.  
  44.   List1.Free;
  45.   List2.Free;
  46. end.

Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

bytebites

  • Hero Member
  • *****
  • Posts: 633
Re: Missing Assign method in RTL-Generics Classes
« Reply #7 on: August 08, 2022, 06:13:17 pm »
List2 was not created
Code: Pascal  [Select][+][-]
  1. List2:=TMyList.Create(List1);  

simone

  • Hero Member
  • *****
  • Posts: 573
Re: Missing Assign method in RTL-Generics Classes
« Reply #8 on: August 08, 2022, 06:37:43 pm »
You are right.  I quickly wrote the code. I created List2 in the wrong way: 

Code: Pascal  [Select][+][-]
  1. List2.Create(List1) //wrong!

Sorry... Thank you.
« Last Edit: August 08, 2022, 06:47:53 pm by simone »
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

simone

  • Hero Member
  • *****
  • Posts: 573
Re: Missing Assign method in RTL-Generics Classes
« Reply #9 on: August 08, 2022, 09:15:18 pm »
My previous example contains another error. Lists that are instances of TObjectList<T>, unless otherwise specified, 'own' the contained elements, since the constructors of this class have the parameter AOwnsObjects set to True by default). So their elements are destroyed when the list is destroyed. Therefore when List2.Feee is executed, an access violation error occurs at run time, beacause the contained objects have already been destroyed by List1.Free. A solution is to create the clone list by setting the AOwnsObjects parameter to False. The correct code is as follows:


Code: Pascal  [Select][+][-]
  1. program Project1;
  2. {$Mode ObjFPC}
  3. uses
  4.   Generics.Collections;
  5. type
  6.  
  7.   { TMyType }
  8.  
  9.   TMyType=class
  10.     Field1 : integer;
  11.     Field2 : integer;
  12.     procedure Write;
  13.     constructor Create(Value1, Value2 : integer);
  14.   end;
  15.  
  16.   TMyList=specialize TObjectList<TMyType>;
  17.  
  18. var
  19.   List1, List2 : TMyList;
  20.   Item : TMyType;
  21.  
  22. { TMyType }
  23.  
  24. procedure TMyType.Write;
  25. begin
  26.   writeln(Field1,'-',Field2);
  27. end;
  28.  
  29. constructor TMyType.Create(Value1, Value2: integer);
  30. begin
  31.   Field1:=Value1;
  32.   Field2:=Value2;
  33. end;
  34.  
  35. begin
  36.   List1:=TMyList.Create;
  37.   List1.Add(TMyType.Create(1,2));
  38.   List1.Add(TMyType.Create(3,4));
  39.   List2:=TMyList.Create(List1,False);
  40.  
  41.   for Item in List2 do
  42.     Item.Write;
  43.  
  44.   List1.Free;
  45.   List2.Free;
  46. end.  
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

 

TinyPortal © 2005-2018