* * *

Author Topic: Management operators and classes?  (Read 921 times)

soerensen3

  • Full Member
  • ***
  • Posts: 113
Management operators and classes?
« on: May 28, 2018, 06:46:06 pm »
Hi,

is something like this also possible for classes?
http://wiki.freepascal.org/management_operators

I hope it to simplify my managed pointer type which works but is way to complicated to use.

I only know of interfaces but I never understood the way reference counting works with them. It seems to be quite complicated: https://www.freepascal.org/docs-html/ref/refse92.html
Lazarus 1.9 with FPC 3.0.4
Target: Manjaro Linux 64 Bit (4.9.68-1-MANJARO)

Thaddy

  • Hero Member
  • *****
  • Posts: 6116
Re: Management operators and classes?
« Reply #1 on: May 28, 2018, 10:06:33 pm »
In trunk this is fully supported and both Maciej (the author, a.k.a HNB) and me already gave some powerful examples on this forum.
It still needs an extra pseudo reference, though..
« Last Edit: May 28, 2018, 10:08:33 pm by Thaddy »
I might not give the answer that you want me to.. Peter Green 1969

hnb

  • Full Member
  • ***
  • Posts: 241
Re: Management operators and classes?
« Reply #2 on: May 28, 2018, 10:19:03 pm »
you can try this library : https://github.com/maciej-izak/PascalSmartPointers

especially this example should be interesting for you : https://github.com/maciej-izak/PascalSmartPointers/blob/master/examples/SmartObj01.pas

note: code with "default field" will work only with http://newpascal.org/ not with FPC stable nor FPC trunk.
Checkout NewPascal initiative and donate beer - ready to use tuned FPC compiler + Lazarus for mORMot project

best regards,
Maciej Izak

soerensen3

  • Full Member
  • ***
  • Posts: 113
Re: Management operators and classes?
« Reply #3 on: May 29, 2018, 12:24:22 am »
Thank you for your answers.
@Thaddy: I couldn't find it somehow, all I could find was the code with the records. I was wondering if these operators also work on classes directly but probably not. This way I could get rid of the pseudo reference. With pseudo reference you mean the record, right?

@hnb: That's the repo that I was looking for. Too bad with the default field but I think it's still useful, because assigning should still work. For now I would like to keep my code compatible but I will definitely give NewPascal a try.
Lazarus 1.9 with FPC 3.0.4
Target: Manjaro Linux 64 Bit (4.9.68-1-MANJARO)

hnb

  • Full Member
  • ***
  • Posts: 241
Re: Management operators and classes?
« Reply #4 on: May 29, 2018, 12:37:51 am »
you can't use management operators in classes, this is possible to implement but may be not worth (I am still considering few scenarios).

maybe someday close cooperation with FPC core team will be possible again (I have hope so), but for now too many bad emotions around, so rather I wouldn't expect any of my new feature (nor any activity) in FPC trunk in near future.
Checkout NewPascal initiative and donate beer - ready to use tuned FPC compiler + Lazarus for mORMot project

best regards,
Maciej Izak

Thaddy

  • Hero Member
  • *****
  • Posts: 6116
Re: Management operators and classes?
« Reply #5 on: May 29, 2018, 09:03:27 am »
you can't use management operators in classes, this is possible to implement but may be not worth (I am still considering few scenarios).

maybe someday close cooperation with FPC core team will be possible again (I have hope so), but for now too many bad emotions around, so rather I wouldn't expect any of my new feature (nor any activity) in FPC trunk in near future.
You can use management operators in classes provided the class has a locally typed and declared record! Because they also work for local records defined inside classes(including the type).
 Is that by accident? You implemented it.... :P
« Last Edit: May 29, 2018, 09:06:42 am by Thaddy »
I might not give the answer that you want me to.. Peter Green 1969

hnb

  • Full Member
  • ***
  • Posts: 241
Re: Management operators and classes?
« Reply #6 on: May 29, 2018, 09:17:14 am »
You can use management operators in classes provided the class has a locally typed and declared record! Because they also work for local records defined inside classes(including the type).
 Is that by accident? You implemented it.... :P

I mean here direct usage like :

Code: Pascal  [Select]
  1. type
  2.   TThaddy = class
  3.   private
  4.     class operator Initialize(var a: TThaddy);
  5.     ...
  6.   end;
  7.  

it has not much sense for now :P
Checkout NewPascal initiative and donate beer - ready to use tuned FPC compiler + Lazarus for mORMot project

best regards,
Maciej Izak

Thaddy

  • Hero Member
  • *****
  • Posts: 6116
Re: Management operators and classes?
« Reply #7 on: May 29, 2018, 09:29:40 am »
Naah, that won't work (probably:yet) indeed, but my scenario happens to work and you can do funny things with it.
Great to hear you seem optimistic about the future....
I might not give the answer that you want me to.. Peter Green 1969

soerensen3

  • Full Member
  • ***
  • Posts: 113
Re: Management operators and classes?
« Reply #8 on: May 29, 2018, 10:58:20 am »
you can't use management operators in classes, this is possible to implement but may be not worth (I am still considering few scenarios).

maybe someday close cooperation with FPC core team will be possible again (I have hope so), but for now too many bad emotions around, so rather I wouldn't expect any of my new feature (nor any activity) in FPC trunk in near future.
You can use management operators in classes provided the class has a locally typed and declared record! Because they also work for local records defined inside classes(including the type).
 Is that by accident? You implemented it.... :P
Thanks! That's pretty smart I will try that when I have time later. I understand the locally declared part, but why locally typed? Because of the generic? I only have one class (and descendants) where I want this behaviour so I don't really need a generic for the record.
Lazarus 1.9 with FPC 3.0.4
Target: Manjaro Linux 64 Bit (4.9.68-1-MANJARO)

Thaddy

  • Hero Member
  • *****
  • Posts: 6116
Re: Management operators and classes?
« Reply #9 on: May 29, 2018, 11:22:13 am »
but why locally typed? Because of the generic? I only have one class (and descendants) where I want this behaviour so I don't really need a generic for the record.
It will probably work with a global type too, but my play garden used a class local type. Note that Maciej wrote it is not implemented for classes. I merely tested a work-around.
I might not give the answer that you want me to.. Peter Green 1969

soerensen3

  • Full Member
  • ***
  • Posts: 113
Re: Management operators and classes?
« Reply #10 on: May 29, 2018, 01:20:45 pm »
Ah damn thinking about it again though it works using a nested record it doesn't solve my problem!  :)
If I copy the class pointer it does not make a new instance of the record.

modified SmartObj.pas
Code: Pascal  [Select]
  1. {
  2.     This file is part of the Free Pascal run time library.
  3.     Copyright (c) 1999-2014 by Maciej Izak aka hnb (NewPascal project)
  4.     See the file COPYING.FPC, included in this distribution,
  5.     for details about the copyright.
  6.     This program is distributed in the hope that it will be useful,
  7.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9.  **********************************************************************}
  10.  
  11.  unit SmartObj;
  12.  
  13. {$MODE DELPHI}
  14.  
  15. interface
  16.  
  17. uses
  18.   SysUtils, Classes;
  19.  
  20. type
  21.  
  22.   { TSmartObj }
  23.  
  24.   TSmartObj = class
  25.     private type TContainer = record
  26.       Instance: TSmartObj;
  27.       RefCount: PLongint;
  28.  
  29.       procedure SmartFinalize();
  30.  
  31.       class operator Initialize(var aRec: TContainer);
  32.       class operator Finalize(var aRec: TContainer);
  33.       class operator AddRef(var aRec: TContainer);
  34.       class operator Copy(constref aSource: TContainer; var aDest: TContainer);
  35.  
  36.       class operator Implicit(aObj: TSmartObj): TContainer;
  37.       procedure Assign(const aValue: TSmartObj);
  38.     end;
  39.  
  40.     private
  41.       Container: TContainer;
  42.  
  43.     public
  44.       constructor Create;
  45.       destructor Destroy; override;
  46.   end;
  47.  
  48. implementation
  49.  
  50. { TSmartObj }
  51.  
  52. constructor TSmartObj.Create;
  53. begin
  54.   inherited Create;
  55.   Container.Instance:= Self;
  56. end;
  57.  
  58. destructor TSmartObj.Destroy;
  59. begin
  60.   Container.Instance:= nil;
  61.   inherited Destroy;
  62. end;
  63.  
  64. procedure TSmartObj.TContainer.SmartFinalize();
  65. begin
  66.   WriteLn( 'SmartFinalize' );
  67.   if RefCount <> nil then
  68.     if InterLockedDecrement(RefCount^)=0 then
  69.     begin
  70.       FreeMem(RefCount);
  71.       Instance.Free;
  72.     end;
  73. end;
  74.  
  75. class operator TSmartObj.TContainer.Initialize(var aRec: TContainer);
  76. begin
  77.   aRec.RefCount := nil;
  78.   WriteLn( 'Initialize' );
  79. end;
  80.  
  81. class operator TSmartObj.TContainer.Finalize(var aRec: TContainer);
  82. begin
  83.   aRec.SmartFinalize();
  84. end;
  85.  
  86. class operator TSmartObj.TContainer.AddRef(var aRec: TContainer);
  87. begin
  88.   WriteLn( 'AddRef' );
  89.   if aRec.RefCount <> nil then
  90.     InterLockedIncrement(aRec.RefCount^);
  91. end;
  92.  
  93. class operator TSmartObj.TContainer.Copy(constref aSource: TContainer;
  94.   var aDest: TContainer);
  95. begin
  96.   WriteLn( 'Copy' );
  97.   if aDest.RefCount <> nil then
  98.     aDest.SmartFinalize();
  99.   if aSource.RefCount <> nil then
  100.     InterLockedIncrement(aSource.RefCount^);
  101.   aDest.RefCount := aSource.RefCount;
  102.   aDest.Instance := aSource.Instance;
  103. end;
  104.  
  105. class operator TSmartObj.TContainer.Implicit(aObj: TSmartObj): TContainer;
  106. begin
  107.   Result.Assign(aObj);
  108. end;
  109.  
  110. procedure TSmartObj.TContainer.Assign(const aValue: TSmartObj);
  111. begin
  112.   WriteLn( 'Assign' );
  113.   if RefCount <> nil then
  114.     SmartFinalize();
  115.  
  116.   GetMem(RefCount, SizeOf(LongInt));
  117.   RefCount^ := 0;
  118.  
  119.   InterLockedIncrement(RefCount^);
  120.   Instance := aValue;
  121. end;
  122.  
  123. end.
Testproject: project1.lpr
Code: Pascal  [Select]
  1. program project1;
  2.  
  3. uses sysutils, SmartObj;
  4.  
  5. var
  6.   Test: TSmartObj;
  7.   Test2: TSmartObj;
  8.  
  9. begin
  10.   Test:= TSmartObj.Create;
  11.   Test2:= Test; // copy/addref is not called because only the pointer of TSmartObj is copied
  12.   //Test:= nil; // no smart finalize here
  13.   FreeAndNil( Test );
  14.   WriteLn( HexStr( @Test2 )); // Should be nil if it was working but it's not
  15. end.
  16.  

So it's only working with the default field if you do not want the user to be dealing with the record. I hope this feature moves to fpc.
Lazarus 1.9 with FPC 3.0.4
Target: Manjaro Linux 64 Bit (4.9.68-1-MANJARO)

ASerge

  • Hero Member
  • *****
  • Posts: 767
Re: Management operators and classes?
« Reply #11 on: May 29, 2018, 08:10:51 pm »
I only know of interfaces but I never understood the way reference counting works with them. It seems to be quite complicated: https://www.freepascal.org/docs-html/ref/refse92.html
In ref example, the call y.DoTest(8) in the Test3 procedure is a very unpredictable thing. In a real program you must never do this! It would be nice if the example also mentioned about this.

 

Recent

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