I keep hearing about the double finalize bug thing, but I've not ran into it myself yet...
I'll need to look into that... (and why I don't get more than one finalize)...
EDIT: OK, looking at this: https://gitlab.com/freepascal.org/fpc/source/-/issues/37164
I've originally discovered it for using enumerators, which is shown in the issue you've linked, with this I then simply used classes or interfaces for enumerators (as enumerators are also automatically freed this is not a problem), but later I also discovered that this bug also occurs in other places, with constructors:
program Project1;
{$mode objfpc}{$H+}
{$ModeSwitch advancedrecords}
uses
{$IFDEF UNIX}
cthreads,
{$ENDIF}
Classes
{ you can add units after this };
type
{ TTestRec }
TTestRec = record
Value: Integer;
class operator Initialize(var rec: TTestRec);
class operator Finalize(var rec: TTestRec);
class operator Copy(constref src: TTestRec; var dst: TTestRec);
class operator AddRef(var rec: TTestRec);
constructor Create(AValue: Integer);
end;
{ TTestRec }
class operator TTestRec.Initialize(var rec: TTestRec);
begin
WriteLn('Init');
end;
class operator TTestRec.Finalize(var rec: TTestRec);
begin
WriteLn('Final');
end;
class operator TTestRec.Copy(constref src: TTestRec; var dst: TTestRec);
begin
WriteLn('Copy');
end;
class operator TTestRec.AddRef(var rec: TTestRec);
begin
WriteLn('AddRef');
end;
constructor TTestRec.Create(AValue: Integer);
begin
Self.Value := AValue;
end;
procedure Test;
var
rec: TTestRec;
begin
rec := TTestRec.Create(42);
end;
begin
Test;
ReadLn;
end.
2 Initializes but 3 finalizes.
And this was quite a discovery process, as I was already working on a project for 2 weekends full time, so I probably spend already like 30-40 hours into a project, and I've noticed that the values where not quite right, but I could not figure out why. Turns out that after the double finalize, the memory was reallocated by something different, so I had multiple record pointers all using the same memory region, without knowing, which meant did not cause any crashs, just that the values did not make sense.
It took me another 10 hours to figure that out, since then I haven't touched managed records (at least those that rely on finalize) again, because such bugs are really hard to find, they usually start occuring deep inside the project, and can cost days to debug.
I really really like the idea of managed records, the project where I discovered this was literally a whole library of types using managed records, lists, dictionairies and sets, file and network streams, etc.
I still think that this would allow for really great and clean code, things like this:
function ReadFile(const AFileName: String): String;
begin
Result := '';
with FileOpen(AFileName, fomRead) do
while not EOF do
Result += ReadLine + NewLine;
end;
But sadly until the double finalize bug is fixed, I don't want to start using them again, just to again after hours upon hours, finding out that something deep down went wrong and I can start completely from scratch.