On 12/21/23 07:06, Hairy Pixels via fpc-pascal wrote:

On Dec 21, 2023, at 6:11 AM, Hairy Pixels <generic...@gmail.com> wrote:

Maybe I misunderstood but I thought they were supposed to be balanced with init 
calls. Is it the design of the compiler to allow multiple finalize calls and 
have the user keep track of it the underlying structure is really finalized or 
not? If you were doing things like deleting memory in the finalizer you would 
have a double free happen here.
Here's another example of this. If I use an array Finalize is called 4 times 
but  Initialize is never called, unless you assign  a record to the array and 
then it's called once.

This makes even less sense. What's the idea behind this behavior? I would 
expect the calls to balanced as this feature is intended for reference counting 
I thought.

Even though it should be possible to implement reference counting, I don't think that's the management operators' primary intended use. Interfaces and creating a class that inherits from TInterfacedObject is the traditional Delphi way to implement reference counting. I tend to think of management operators as a way to do a C++ way of managed objects, passed by value. That includes not just Initialize and Finalize (in C++ these are constructors and destructors), but also Copy as well (in C++, this is done by the copy constructor and the assignment operator).

If I wanted to use reference counting, I would still use interfaces and TInterfacedObject.

If I wanted to create a new value type that uses memory on the heap, I would implement not just Initialize and Finalize, but also Copy and probably AddRef (although I don't know when AddRef is used).

However, I think of management operators as a newer and less stable feature, so I think that double Finalize call is a bug, that happens when a function result is discarded, which is allowed in the extended syntax {$X+} mode. Management operators were, unfortunately, added by a developer, who had disagreements with the other core FPC developers and started an FPC fork, called NewPascal. So it's possible some of the features he added were not as stable or as finished as they should be.

That's why I would use interfaces and TInterfacedObject if I wanted just reference counting.

Btw, I used management operators in my Unicode-enabled version of the KVM units and Free Vision:

https://wiki.freepascal.org/Free_Vision#Unicode_version

See the TEnhancedVideoCell record in:

https://gitlab.com/freepascal.org/fpc/source/-/blob/main/packages/rtl-console/src/inc/videoh.inc

It enables us to save memory when a character cell is represented by a single Unicode code point in the BMP range, but still support complex graphemes (which can contain a sequence of unicode code points - combining characters, etc.) allocated on the heap when necessary.

So, I don't have hesitance in using them when they are the best choice, it's just that I consider them less stable and expect bugs. I just don't think they're the best for implementing reference counting.

Nikolay



==============================

{$mode objfpc}
{$modeswitch advancedrecords}

program test;

type
  TManagedObject = record
    x: integer;
    class operator Finalize(var self: TManagedObject); inline;
    class operator Initialize(var self: TManagedObject); inline;
  end;

class operator TManagedObject.Finalize(var self: TManagedObject);
begin
  writeln('Finalize');
end;

class operator TManagedObject.Initialize(var self: TManagedObject);
begin
  writeln('Initialize');
end;

var
  a: array[0..3] of TManagedObject;
begin
  a[0].x := 1;
  a[1].x := 1;
  a[2].x := 1;
  a[3].x := 1;
end.

Regards,
Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
_______________________________________________
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal

Reply via email to