Default, Manual Initialize, or Automatic Initialize lazarus / 64-FPC development ---------------------------------------------------------------------- Okoba · 2026-01-20 12:43 Hello, I am still confused by how should I use manage records. As you can see by the tests and their output (latest FPC), I need some help to understand: 1- TestManagedRecord seems working but you get a (wrong?) warning. Is this a correct code? Is the warning wrong and a bug? 2- TestManagedRecordWithDefault is also working but seems inappropriate and slow if you are using this code a lot as you Initialize twice, one for default and one automatic by the compiler. 3- TestManagedRecordParent fine also, but issues as point 1. 4- TestManagedRecordParentWithDefault, it is wrong as clears the memory. It should be wrong and I think is a bug in FPC, correct? If I don't use Default for TManagedRecordParent, any other property would have garbage as it is not initialized, and if I call Initialize it does not change it as it does not have Initialize operator. Am I forced to add Initialize operator to all the records using a managed record?! 5- TestManagedRecordParentWithInitialize working again but problems issues as point 2. What is the correct way of working with managed records? When I mean correct, I mean stable and no bug, fast and no redundant compiler warning. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program Project1; {$mode delphi} type  TManagedRecord = record    A: Integer;    class operator Initialize(var ATest: TManagedRecord);    class operator Finalize(var ATest: TManagedRecord);  end;   class operator TManagedRecord.Initialize(var ATest: TManagedRecord);  begin    WriteLn('Initialize');    ATest.A := -1;  end;   class operator TManagedRecord.Finalize(var ATest: TManagedRecord);  begin    WriteLn('Finalize');    ATest.A := -1;  end; type  TManagedRecordParent = record    Test: TManagedRecord;  end;   //Output:  //Initialize  //-1  //Finalize   //Correct but compiler warning: Local variable "T" of a managed type does not seem to be initialized  procedure TestManagedRecord;  var    T: TManagedRecord;  begin    WriteLn(T.A);  end;   //Output:  //Initialize (For Default)  //Initialize  //-1  //Finalize  procedure TestManagedRecordWithDefault;  var    T: TManagedRecord;  begin    T := Default(TManagedRecord);    WriteLn(T.A);  end;   //Output:  //Initialize  //-1  //Finalize   //Correct but compiler warning: Local variable "T" of a managed type does not seem to be initialized  procedure TestManagedRecordParent;  var    T: TManagedRecordParent;  begin    WriteLn(T.Test.A);  end;   //Output: (No Initialize for default)  //Initialize  //0  //Finalize   //Wrong!  procedure TestManagedRecordParentWithDefault;  var    T: TManagedRecordParent;  begin    T := Default(TManagedRecordParent);    WriteLn(T.Test.A);  end;   //Output:  //Initialize  //Initialize  //-1  //Finalize   //Correct but double Initialize, first automatic by the compiler and second manual Initialize(T);  procedure TestManagedRecordParentWithInitialize;  var    T: TManagedRecordParent;  begin    Initialize(T);    WriteLn(T.Test.A);  end; begin  TestManagedRecord;  TestManagedRecordWithDefault;  TestManagedRecordParent;  TestManagedRecordParentWithDefault;  TestManagedRecordParentWithInitialize;end. ---------------------------------------------------------------------- andersonscinfo · 2026-01-20 12:44 Olá, Seu código demonstra bem os diferentes comportamentos dos registros gerenciados no FPC. Vamos analisar cada ponto: 1. **TestManagedRecord**: O compilador avisa que a variável local `T` não parece estar inicializada, mas isso é apenas um aviso. O operador `Initialize` é chamado automaticamente antes da primeira utilização do registro, então o código está correto. O aviso é um falso positivo do compilador, mas não afeta a execução. 2. **TestManagedRecordWithDefault**: Ao usar `Default(TManagedRecord)`, você força uma inicialização explícita (chamando `Initialize`) e o compilador também chama `Initialize` automaticamente. Isso resulta em duas chamadas, o que é redundante e mais lento. Evite usar `Default()` com registros gerenciados que têm operadores `Initialize`. 3. **TestManagedRecordParent**: Semelhante ao primeiro caso, o aviso é um falso positivo. O campo `Test` do tipo `TManagedRecord` dentro de `TManagedRecordParent` é automaticamente inicializado pelo compilador, acionando o `Initialize` de `TManagedRecord`. 4. **TestManagedRecordParentWithDefault**: Aqui está o ponto crítico. Quando você faz `T := Default(TManagedRecordParent);`, o valor padrão de `TManagedRecordParent` é atribuído. Como `TManagedRecord` não tem um valor padrão explícito definido (além do que o `Default` aplica implicitamente, que é zero), o campo `Test` é inicializado com zeros. Isso significa que `Test.A` será 0, e o `Initialize` não é chamado automaticamente porque o compilador considera o registro já "inicializado" com o valor padrão. Portanto, o `Initialize` interno (`TManagedRecord`) não é chamado, e o valor impresso é 0. Isso não é um bug, é o comportamento esperado do `Default`. O `Default` não chama os operadores `Initialize`, ele simplesmente define os campos para seus valores padrão (zero para tipos primitivos). 5. **TestManagedRecordParentWithInitialize**: Usar `Initialize(T)` chama explicitamente o inicializador do registro. No caso de `TManagedRecordParent`, isso chama o `Initialize` de `TManagedRecord` (porque `Test` é um campo de `TManagedRecord`). Isso é redundante com a inicialização automática do compilador, resultando em duas chamadas de `Initialize`. ### Conclusão O comportamento correto e mais eficiente é o demonstrado em `TestManagedRecord` e `TestManagedRecordParent`. O compilador cuida automaticamente da inicialização e finalização dos registros gerenciados. Os avisos são falsos positivos e podem ser ignorados ou suprimidos com `$warnings off`. Evite o uso de `Default()` com registros gerenciados que possuem `Initialize`, pois isso pode levar a inicializações duplas ou comportamentos inesperados. Usar `Initialize(T)` explicitamente também deve ser evitado, a menos que você tenha um motivo específico e entenda as implicações (como reinicializar um registro já inicializado). Portanto, a forma mais segura, rápida e sem avisos é confiar na inicialização automática do compilador, como em `TestManagedRecord` e `TestManagedRecordParent`, e talvez adicionar `{$warnings off}` se os avisos forem incômodos. Att. ---------------------------------------------------------------------- Thausand · 2026-01-20 13:01 warning, is clanker. ---------------------------------------------------------------------- Thaddy · 2026-01-20 13:21 @andersonscinfo Can you please stop giving elaborate wrong answers? I do too, but your proze is always wrong and people will not even try to correct it? ---------------------------------------------------------------------- Okoba · 2026-01-20 13:23 @Thaddy like you he does not care Do you have an answer for the question? ---------------------------------------------------------------------- Thaddy · 2026-01-20 13:25 Your original code works correctly in trunk but possibly not in 3.2.x: Code: Text  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i InitializeI nitialize-1FinalizeInitialize-1FinalizeInitialize- 1FinalizeInitialize0FinalizeInitializeInitialize-1FinalizeFinalizeHeap dump by heaptrc unit of "c:\Users\thadd\inlinetest.exe"0 memory blocks allocated : 00 memory blocks freed     : 00 unfreed memory blocks : 0True heap size : 65536 (128 used in System startup)True free heap : 65408 There was a problem in the past, but fixed. The "not initialized" warnings can be ignored. ---------------------------------------------------------------------- Okoba · 2026-01-20 13:33 I am using Trunk. What do you mean correct? Please notice the point 4. What should be done about TManagedRecordParent? If I leave it be, it contains garbage data for other properties and if I Default it, it will clear the TManagedRecord too. What should be done about the warnings? Is it a bug? ---------------------------------------------------------------------- H₂SO₄ · 2026-01-20 14:22 The following procedure... Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure Foo();var  Bar: TManagedRecord;begin  WriteLn(Bar.A);end; ...is essentially the same as this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure Foo();var  Bar: TManagedRecord_without_automatic_invocation_of_managem ent_operators;begin  fpc_initialize(@Bar, TypeInfo(Bar));  try    WriteLn(Bar.A);  finally    fpc_finalize(@Bar, TypeInfo(Bar));  end;end; fpc_initialize  simply calls  Initialize  for the given type (if the operator is present, that is). This means that the warning is in fact justified, but shows up in a misleading place; it's the  var  parameter passed to  Initialize  that might not be initialized. But if you don't use that initial value in  Initialize  (as is normally the case), this warning is nothing but noise. Regarding  Default,  I'm not sure what the correct behavior is - to me it seems like all it should do is zero out its target while making sure to call the  Copy  operator for managed types. I also can't reproduce  TestManagedRecordWithDefault  on FPC 3.2.2; the output I get is "0", not "-1". ---------------------------------------------------------------------- Okoba · 2026-01-20 14:39 "TManagedRecord_without_automatic_invocation_of_management_operators" this one seems like a bug. When you Initialize a type, it is expected to get initialized value, including sub properties. I hope to get a clarification from the FPC team. ---------------------------------------------------------------------- LeP · 2026-01-20 14:41 Quote from: Thaddy on January 20, 2026, 02:25:05 pmYour original code works correctly in trunk but possibly not in 3.2.x: Code: Text  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i InitializeI nitialize-1FinalizeInitialize-1FinalizeInitialize- 1FinalizeInitialize0FinalizeInitializeInitialize-1FinalizeFinalizeHeap dump by heaptrc unit of "c:\Users\thadd\inlinetest.exe"0 memory blocks allocated : 00 memory blocks freed     : 00 unfreed memory blocks : 0True heap size : 65536 (128 used in System startup)True free heap : 65408 There was a problem in the past, but fixed. The "not initialized" warnings can be ignored.  I try this in Delphi (without change anything except adds MemoryLeak report) and I found little bit differences: QuoteInitialize -1 Finalize Initialize Finalize Initialize -1 Finalize Initialize -1 Finalize Initialize Finalize Initialize -1 Finalize Initialize Initialize -1 Finalize P.S.: no warnings at compiled time ---------------------------------------------------------------------- Okoba · 2026-01-20 18:25 That seems the correct output and behavior by the compiler. Thank you for the test. ---------------------------------------------------------------------- PascalDragon · 2026-01-20 20:23 Quote from: andersonscinfo on January 20, 2026, 01:44:55 pmSeu código demonstra bem os diferentes comportamentos dos registros gerenciados no FPC. Vamos analisar cada ponto: Please only write in English in the international part of the forum. Also the forum does not support MarkDown. You need to use the BBCodes that it provides for formatting. ---------------------------------------------------------------------- Okoba · 2026-01-20 21:23 @PascalDragon here is your place to share your compiler knowledge please. ---------------------------------------------------------------------- PascalDragon · 2026-01-20 22:03 Just the record type is the correct one, so your TestManagedRecord and ignore the compiler message. I personally am in favor for removing it for local variables of managed types, but fpk is not. 🤷‍♀️ ---------------------------------------------------------------------- H₂SO₄ · 2026-01-21 06:16 Quote from: Okoba on January 20, 2026, 03:39:42 pm"TManagedRecord_with out_automatic_invocation_of_management_operators" this one seems like a bug. When you Initialize a type, it is expected to get initialized value, including sub properties. I hope to get a clarification from the FPC team. Sorry, that was just me being facetious about correctness. I meant to make the two snippets as similiar as possible in their produced assembly, but that would require that  TManagedRecord  be both not managed by the compiler while at the same time providing management operator implementations (which is impossible). If you tried to actually compile the second snippet there would be two  fpc_initialize, try/finally, fpc_finalize  constructs because of that. I just wanted to show where the "uninitialized managed local variable" warning comes from. ---------------------------------------------------------------------- Okoba · 2026-01-21 08:17 @PascalDragon what about TestManagedRecordParent? If it has other properties, they will be left uninitialized, and I have two way, either add Initialize for every record that uses it, or use Default and it cancels the manage record Initialize. Is there a distinction between this warn and others so I can disable these only? I try to not have such errors in my code to prevent bugs, but ignoring compiler warn seems risky @Khrys thank you for the clarification. Records are great but this manage part needs some improvement. ---------------------------------------------------------------------- Okoba · 2026-02-01 19:41 This topic is still not resolved to me, please add your thoughts. ---------------------------------------------------------------------- H₂SO₄ · 2026-02-02 07:01 Quote from: Okoba on January 21, 2026, 09:17:22 amIs there a distinction between this warn and others so I can disable these only? Yes, there's a four-way distinction to these messages: managed vs unmanaged, local vs global, function result vs non-function result, warning vs hint: 5036 WARN Local variable does not seem to be initialized 5037 WARN Variable does not seem to be initialized 5057 HINT Local variable does not seem to be initialized 5058 HINT Variable does not seem to be initialized 5059 WARN Function result variable does not seem to be initialized 5060 HINT Function result variable does not seem to be initialized 5089 WARN Local variable of a managed type does not seem to be initialized 5090 WARN Variable of a managed type does not seem to be initialized 5091 HINT Local variable of a managed type does not seem to be initialized 5092 HINT Variable of a managed type does not seem to be initialized 5093 WARN Function result variable of a managed type does not seem to be initialized 5094 HINT Function result variable of a managed type does not seem to be initialized Quote from: Okoba on January 21, 2026, 09:17:22 amI try to not have such errors in my code to prevent bugs, but ignoring compiler warn seems risky The only circumstance in which these messages carry any weight is when the respective managed type does not implement  class operator Initialize,  so just make sure to always provide it. ---------------------------------------------------------------------- Okoba · 2026-02-02 07:15 You mean I need to implement Initialize operator for all my records? ---------------------------------------------------------------------- H₂SO₄ · 2026-02-02 07:31 Quote from: Okoba on February 02, 2026, 08:15:44 amYou mean I need to implement Initialize operator for all my records? Only for your managed record types. If all managed record types that you use have that operator, then the aforementioned warnings can be safely ignored by switching them off (i.e. at the project level). For example, in the following case, the warning will appear and it will be justified because there is no  Initialize  operator: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i type  TAutoFree = record    Data: Pointer;    class operator Finalize(var Self: TAutoFree);  end; class operator TAutoFree.Finalize(var Self: TAutoFree);begin  FreeMem(Self.Data);  Self.Data := Nil;end; procedure Foo();var  Buffer: TAutoFree;begin  // `Buffer` wasn't initialized -> CRASH AND BURN on `FreeMem`end;  However, if you make sure to implement  Initialize,  then the warning is meaningless (even though it still appears): Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i type  TAutoFree = record    Data: Pointer;    class operator Initialize(var Self: TAutoFree);    class operator Finalize(var Self: TAutoFree);  end; class operator TAutoFree.Initialize(var Self: TAutoFree);begin  Self.Data := Nil;end; class operator TAutoFree.Finalize(var Self: TAutoFree);begin  FreeMem(Self.Data);  Self.Data := Nil;end; procedure Foo();var  Buffer: TAutoFree;begin  // `Buffer.Data` is set to `Nil` -> `FreeMem` does nothingend; ---------------------------------------------------------------------- 440bx · 2026-02-02 08:15 Quote from: Khrys on February 02, 2026, 08:01:20 am 5036 WARN Local variable does not seem to be initialized 5037 WARN Variable does not seem to be initialized 5057 HINT Local variable does not seem to be initialized 5058 HINT Variable does not seem to be initialized 5059 WARN Function result variable does not seem to be initialized 5060 HINT Function result variable does not seem to be initialized Generally speaking I think it is "prudent" to write code in such a way that _none_ of the above hints and warnings are emitted by the compiler. Even something as simple as a local variable not being initialized can be the cause of a hard to find bug because the value of the local variable is unpredictable. I think it is simply good programming to _always_ initialize _all_ variables. I think the bad habit of not initializing all variables as a matter of course comes from the obsession of making code as fast as possible.  I think an obsession of making the code _correct_ is a much more useful and justified obsession.  That said, I stopped using FPC's "= ();" to initialize records because of the outrageously bad code it generates, now I just ZeroMemory the things. As far as initializing records, I believe that every record should have an "Init" procedure that sets _all_ of its fields to appropriate default values.  Here, I have to admit that while I more often than not do that, there are times when I skip that step (usually for code I consider "not important".)  I mention this because I don't want to appear to be one of those "do as I say, not as I do". Anyway, initializing variables only costs a few clock cycles, in today's 4 to 6 Ghz machines, it would really take a lot of initializations to make a perceptible difference in the execution time but, it can definitely make a very perceptible difference in the amount of time spent (not) debugging the program. ---------------------------------------------------------------------- H₂SO₄ · 2026-02-02 08:32 Quote from: 440bx on February 02, 2026, 09:15:24 amQuote from: Khrys on February 02, 2026, 08:01:20 am 5036 WARN Local variable does not seem to be initialized 5037 WARN Variable does not seem to be initialized 5057 HINT Local variable does not seem to be initialized 5058 HINT Variable does not seem to be initialized 5059 WARN Function result variable does not seem to be initialized 5060 HINT Function result variable does not seem to be initialized Generally speaking I think it is "prudent" to write code in such a way that _none_ of the above hints and warnings are emitted by the compiler. I absolutely agree. I just included those to demonstrate the distinction between managed and non-managed types and that it's possible to selectively ignore only the warnings related to the former. ---------------------------------------------------------------------- Okoba · 2026-02-02 20:36 I agree that values should be initialized and that is why I care about the warnings. My problem is that showing warning for records with Initialize operator makes the code dangerous as you only can ignore them by eye or by conditioning the compiler and both make you miss the really missed ones. ---------------------------------------------------------------------- Thaddy · 2026-02-04 15:26 instead of the initialize operator you could also call the global initialize() function on it, depending on use. ---------------------------------------------------------------------- Okoba · 2026-02-05 09:48 It will cause double initialize, one automatic by the compiler and one manual by calling initialize(). Honestly I do not know if I am confused with this current situation or the FPC record design is confusing/wrong. ---------------------------------------------------------------------- Thaddy · 2026-02-05 14:06 In the case I mentioned of course do not write management operators for the record.