[fpc-pascal] Double finalize

Nikolay Nikolov nickysn at gmail.com
Thu Dec 21 06:58:27 CET 2023


On 12/21/23 07:06, Hairy Pixels via fpc-pascal wrote:
>
>> On Dec 21, 2023, at 6:11 AM, Hairy Pixels <genericptr at 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 at lists.freepascal.org
> https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


More information about the fpc-pascal mailing list