Lazarus

Programming => General => Topic started by: simone on August 08, 2022, 03:06:49 pm

Title: Missing Assign method in RTL-Generics Classes
Post by: simone 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.
Title: Re: Missing Assign method in RTL-Generics Classes
Post by: marcov 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.
Title: Re: Missing Assign method in RTL-Generics Classes
Post by: Thaddy 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.
Title: Re: Missing Assign method in RTL-Generics Classes
Post by: simone on August 08, 2022, 04:04:45 pm
I think you don't read before you write (again).

(removed after Thaddy's rectification)
Title: Re: Missing Assign method in RTL-Generics Classes
Post by: Thaddy on August 08, 2022, 04:17:37 pm
No. If you payed attention the issue was solved. Added explanation of TEnumerable<T>, though.
Title: Re: Missing Assign method in RTL-Generics Classes
Post by: simone 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)
Title: Re: Missing Assign method in RTL-Generics Classes
Post by: simone 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.

Title: Re: Missing Assign method in RTL-Generics Classes
Post by: bytebites on August 08, 2022, 06:13:17 pm
List2 was not created
Code: Pascal  [Select][+][-]
  1. List2:=TMyList.Create(List1);  
Title: Re: Missing Assign method in RTL-Generics Classes
Post by: simone 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.
Title: Re: Missing Assign method in RTL-Generics Classes
Post by: simone 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.  
TinyPortal © 2005-2018