Bookstore

Recent

Author Topic: Using record management operators  (Read 486 times)

avk

  • Sr. Member
  • ****
  • Posts: 256
    • my self-education project
Using record management operators
« on: February 26, 2020, 10:00:07 am »
Suppose we have a record that implements management operators:
Code: Pascal  [Select]
  1. type
  2.   TMyManagedRec = record
  3.     Field1: TField1;
  4.     Field2: TField2;
  5.     ...
  6.     class operator Initialize(var r: TMyManagedRec);
  7.     class operator Finalize(var r: TMyManagedRec);
  8.     class operator Copy(constref aSrc: TMyManagedRec; var aDst: TMyManagedRec);
  9.     class operator AddRef(var r: TMyManagedRec);
  10.     ...
  11.   end;
  12.  
We also have some generic record
Code: Pascal  [Select]
  1. type
  2.   generic TGenericRec<T> = record
  3.     SomeField: TSomeField;
  4.     AnotherField: TAnotherField;
  5.     ...
  6.     GenField: T;
  7.   end;
  8.  
that we want to specialize with this managed record:
Code: Pascal  [Select]
  1. type
  2.   TMySpecRec = specialize TGenericRec<TMyManagedRec>;
  3.  

Is any additional effort needed to make this specialized record managed?

eljo

  • Full Member
  • ***
  • Posts: 164
Re: Using record management operators
« Reply #1 on: February 26, 2020, 10:13:47 am »
the specialization is applied to what field is declared as T not the generic record it self. that means that the field gets the "managed" extensions not the generic record it self. You have to write a managed generic record and specialize the unmanaged part and that is extremely complicated.

avk

  • Sr. Member
  • ****
  • Posts: 256
    • my self-education project
Re: Using record management operators
« Reply #2 on: February 26, 2020, 01:22:50 pm »
To be honest, I don't understand what question you're answering.
If we run this simple code:
Code: Pascal  [Select]
  1. program test;
  2.  
  3. {$mode objfpc}
  4. {$modeswitch advancedrecords}
  5.  
  6. uses
  7.   SysUtils;
  8.  
  9. type
  10.  
  11.   TMyManagedRec = record
  12.     Field: Integer;
  13.     class operator Initialize(var r: TMyManagedRec);
  14.     class operator Copy(constref aSrc: TMyManagedRec; var aDst: TMyManagedRec);
  15.   end;
  16.  
  17.   generic TGenericRec<T> = record
  18.     SomeField: Integer;
  19.     GenField: T;
  20.   end;
  21.  
  22.   TMyRecSpec = specialize TGenericRec<TMyManagedRec>;
  23.  
  24. class operator TMyManagedRec.Initialize(var r: TMyManagedRec);
  25. begin
  26.   r.Field := 101;
  27. end;
  28.  
  29. class operator TMyManagedRec.Copy(constref aSrc: TMyManagedRec; var aDst: TMyManagedRec);
  30. begin
  31.   if @aSrc <> @aDst then
  32.     aDst.Field := aSrc.Field + 100;
  33. end;
  34.  
  35. var
  36.   MyRec, MyRec2: TMyRecSpec;
  37.  
  38. begin
  39.   if IsManagedType(TMyRecSpec) then
  40.     begin
  41.       WriteLn('Yes, it is managed type...');
  42.       WriteLn('MyRec.GenField.Field = ', MyRec.GenField.Field);
  43.       WriteLn('MyRec2.GenField.Field = ', MyRec2.GenField.Field);
  44.       MyRec2 := MyRec;
  45.       WriteLn('MyRec2.GenField.Field = ', MyRec2.GenField.Field);
  46.     end
  47.   else
  48.     WriteLn('No, it is not managed type...');
  49. end.  
  50.  
it will print
Code: Text  [Select]
  1. Yes, it is managed type...
  2. MyRec.GenField.Field = 101
  3. MyRec2.GenField.Field = 101
  4. MyRec2.GenField.Field = 201
  5.  
So far so good, but if we complicate the example a bit:
Code: Pascal  [Select]
  1. program test2;
  2.  
  3. {$mode objfpc}
  4. {$modeswitch advancedrecords}
  5.  
  6. uses
  7.   SysUtils;
  8.  
  9. type
  10.  
  11.   TMyManagedRec = record
  12.     Field1: Integer;
  13.     Field2: Single;
  14.     class operator Initialize(var r: TMyManagedRec);
  15.     class operator Copy(constref aSrc: TMyManagedRec; var aDst: TMyManagedRec);
  16.   end;
  17.  
  18.   generic TGenericRec<T> = record
  19.     SomeField: Integer;
  20.     GenField: T;
  21.   end;
  22.  
  23.   TMyRecSpec = specialize TGenericRec<TMyManagedRec>;
  24.  
  25. class operator TMyManagedRec.Initialize(var r: TMyManagedRec);
  26. begin
  27.   r.Field1 := 101;
  28.   r.Field2 := 2.5;
  29. end;
  30.  
  31. class operator TMyManagedRec.Copy(constref aSrc: TMyManagedRec; var aDst: TMyManagedRec);
  32. begin
  33.   if @aSrc <> @aDst then
  34.     begin
  35.       aDst.Field1 := aSrc.Field1 + 100;
  36.       aDst.Field2 := aSrc.Field2 + 4.1;
  37.     end;
  38. end;
  39.  
  40. var
  41.   MyRec, MyRec2: TMyRecSpec;
  42.  
  43. begin
  44.   if IsManagedType(TMyRecSpec) then
  45.     begin
  46.       WriteLn('Yes, it is managed type...');
  47.       WriteLn('MyRec.GenField.Field1 = ', MyRec.GenField.Field1);
  48.       WriteLn('MyRec.GenField.Field2 = ', MyRec.GenField.Field2);
  49.       WriteLn('MyRec2.GenField.Field1 = ', MyRec2.GenField.Field1);
  50.       WriteLn('MyRec2.GenField.Field2 = ', MyRec2.GenField.Field2);
  51.       MyRec2 := MyRec;
  52.       WriteLn('MyRec2.GenField.Field1 = ', MyRec2.GenField.Field1);
  53.       WriteLn('MyRec2.GenField.Field2 = ', MyRec2.GenField.Field2);
  54.     end
  55.   else
  56.     WriteLn('No, it is not managed type...');
  57. end.  
  58.  
answer is:
Code: Text  [Select]
  1. Yes, it is managed type...
  2. MyRec.GenField.Field1 = 101
  3. MyRec.GenField.Field2 = 2,5
  4. MyRec2.GenField.Field1 = 101
  5. MyRec2.GenField.Field2 = 2,5
  6. MyRec2.GenField.Field1 = 201
  7. MyRec2.GenField.Field2 = 2,5
  8.  
That is, the "Copy" operator was not fully executed.
« Last Edit: February 26, 2020, 01:29:17 pm by avk »

ASerge

  • Hero Member
  • *****
  • Posts: 1491
Re: Using record management operators
« Reply #3 on: February 26, 2020, 11:58:21 pm »
answer is:
Code: Text  [Select]
  1. Yes, it is managed type...
  2. MyRec.GenField.Field1 = 101
  3. MyRec.GenField.Field2 = 2,5
  4. MyRec2.GenField.Field1 = 101
  5. MyRec2.GenField.Field2 = 2,5
  6. MyRec2.GenField.Field1 = 201
  7. MyRec2.GenField.Field2 = 2,5
  8.  
That is, the "Copy" operator was not fully executed.
On my machine, your example displays:
Code: Text  [Select]
  1. Yes, it is managed type...
  2. MyRec.GenField.Field1 = 101
  3. MyRec.GenField.Field2 =  2.500000000E+00
  4. MyRec2.GenField.Field1 = 101
  5. MyRec2.GenField.Field2 =  2.500000000E+00
  6. MyRec2.GenField.Field1 = 201
  7. MyRec2.GenField.Field2 =  6.599999905E+00
FPC 3.3.1 (revision 44245), Win x64.

avk

  • Sr. Member
  • ****
  • Posts: 256
    • my self-education project
Re: Using record management operators
« Reply #4 on: February 27, 2020, 04:18:45 am »
@ASerge, thanks, good idea to update the compiler.
Nevertheless, I have another example that works as expected in one case, but fails in another(I apologize for the large size of the example).

PascalDragon

  • Hero Member
  • *****
  • Posts: 1092
  • Compiler Developer
Re: Using record management operators
« Reply #5 on: February 27, 2020, 09:46:42 am »
Is any additional effort needed to make this specialized record managed?

By definition a record that contains a managed type (be it String, dynamic array, interface or record with management operators) is managed by itself and contained fields should be handled accordingly (modulo bugs of course).

answer is:
Code: Text  [Select]
  1. Yes, it is managed type...
  2. MyRec.GenField.Field1 = 101
  3. MyRec.GenField.Field2 = 2,5
  4. MyRec2.GenField.Field1 = 101
  5. MyRec2.GenField.Field2 = 2,5
  6. MyRec2.GenField.Field1 = 201
  7. MyRec2.GenField.Field2 = 2,5
  8.  
That is, the "Copy" operator was not fully executed.
On my machine, your example displays:
Code: Text  [Select]
  1. Yes, it is managed type...
  2. MyRec.GenField.Field1 = 101
  3. MyRec.GenField.Field2 =  2.500000000E+00
  4. MyRec2.GenField.Field1 = 101
  5. MyRec2.GenField.Field2 =  2.500000000E+00
  6. MyRec2.GenField.Field1 = 201
  7. MyRec2.GenField.Field2 =  6.599999905E+00
FPC 3.3.1 (revision 44245), Win x64.

It fails for me as well on i386-win32 and that really makes no sense... @avk would you please report a bug with this relatively simple example? Maybe solving this will solve your more complicated one as well.

avk

  • Sr. Member
  • ****
  • Posts: 256
    • my self-education project
Re: Using record management operators
« Reply #6 on: February 27, 2020, 02:03:58 pm »
By definition a record that contains a managed type (be it String, dynamic array, interface or record with management operators) is managed by itself and contained fields should be handled accordingly.
Yes, I was also very surprised.
At first I thought that the problem is related to generics, but it also affects regular records. I reported a bug.