Recent

Author Topic: Default, Manual Initialize, or Automatic Initialize  (Read 1437 times)

Okoba

  • Hero Member
  • *****
  • Posts: 648
Default, Manual Initialize, or Automatic Initialize
« on: January 20, 2026, 01:43:25 pm »
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][+][-]
  1. program Project1;
  2.  
  3. {$mode delphi}
  4.  
  5. type
  6.   TManagedRecord = record
  7.     A: Integer;
  8.     class operator Initialize(var ATest: TManagedRecord);
  9.     class operator Finalize(var ATest: TManagedRecord);
  10.   end;
  11.  
  12.   class operator TManagedRecord.Initialize(var ATest: TManagedRecord);
  13.   begin
  14.     WriteLn('Initialize');
  15.     ATest.A := -1;
  16.   end;
  17.  
  18.   class operator TManagedRecord.Finalize(var ATest: TManagedRecord);
  19.   begin
  20.     WriteLn('Finalize');
  21.     ATest.A := -1;
  22.   end;
  23.  
  24. type
  25.   TManagedRecordParent = record
  26.     Test: TManagedRecord;
  27.   end;
  28.  
  29.   //Output:
  30.   //Initialize
  31.   //-1
  32.   //Finalize
  33.  
  34.   //Correct but compiler warning: Local variable "T" of a managed type does not seem to be initialized
  35.   procedure TestManagedRecord;
  36.   var
  37.     T: TManagedRecord;
  38.   begin
  39.     WriteLn(T.A);
  40.   end;
  41.  
  42.   //Output:
  43.   //Initialize (For Default)
  44.   //Initialize
  45.   //-1
  46.   //Finalize
  47.   procedure TestManagedRecordWithDefault;
  48.   var
  49.     T: TManagedRecord;
  50.   begin
  51.     T := Default(TManagedRecord);
  52.     WriteLn(T.A);
  53.   end;
  54.  
  55.   //Output:
  56.   //Initialize
  57.   //-1
  58.   //Finalize
  59.  
  60.   //Correct but compiler warning: Local variable "T" of a managed type does not seem to be initialized
  61.   procedure TestManagedRecordParent;
  62.   var
  63.     T: TManagedRecordParent;
  64.   begin
  65.     WriteLn(T.Test.A);
  66.   end;
  67.  
  68.   //Output: (No Initialize for default)
  69.   //Initialize
  70.   //0
  71.   //Finalize
  72.  
  73.   //Wrong!
  74.   procedure TestManagedRecordParentWithDefault;
  75.   var
  76.     T: TManagedRecordParent;
  77.   begin
  78.     T := Default(TManagedRecordParent);
  79.     WriteLn(T.Test.A);
  80.   end;
  81.  
  82.   //Output:
  83.   //Initialize
  84.   //Initialize
  85.   //-1
  86.   //Finalize
  87.  
  88.   //Correct but double Initialize, first automatic by the compiler and second manual Initialize(T);
  89.   procedure TestManagedRecordParentWithInitialize;
  90.   var
  91.     T: TManagedRecordParent;
  92.   begin
  93.     Initialize(T);
  94.     WriteLn(T.Test.A);
  95.   end;
  96.  
  97. begin
  98.   TestManagedRecord;
  99.   TestManagedRecordWithDefault;
  100.   TestManagedRecordParent;
  101.   TestManagedRecordParentWithDefault;
  102.   TestManagedRecordParentWithInitialize;
  103. end.
  104.  
« Last Edit: January 20, 2026, 02:14:49 pm by Okoba »

andersonscinfo

  • Full Member
  • ***
  • Posts: 156
Re: Default, Manual Initialize, or Automatic Initialize
« Reply #1 on: January 20, 2026, 01:44:55 pm »
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

  • Sr. Member
  • ****
  • Posts: 458
Re: Default, Manual Initialize, or Automatic Initialize
« Reply #2 on: January 20, 2026, 02:01:31 pm »
warning, is clanker.

Thaddy

  • Hero Member
  • *****
  • Posts: 18728
  • To Europe: simply sell USA bonds: dollar collapses
Re: Default, Manual Initialize, or Automatic Initialize
« Reply #3 on: January 20, 2026, 02:21:16 pm »
@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?
If Europe sells their USA bonds the USD will collapse. Europe can affort that given average state debts. The USA can't affort that. Just an advice...

Okoba

  • Hero Member
  • *****
  • Posts: 648
Re: Default, Manual Initialize, or Automatic Initialize
« Reply #4 on: January 20, 2026, 02:23:15 pm »
@Thaddy like you he does not care :)
Do you have an answer for the question?

Thaddy

  • Hero Member
  • *****
  • Posts: 18728
  • To Europe: simply sell USA bonds: dollar collapses
Re: Default, Manual Initialize, or Automatic Initialize
« Reply #5 on: January 20, 2026, 02:25:05 pm »
Your original code works correctly in trunk but possibly not in 3.2.x:
Code: Text  [Select][+][-]
  1. Initialize
  2. Initialize
  3. -1
  4. Finalize
  5. Initialize
  6. -1
  7. Finalize
  8. Initialize
  9. -1
  10. Finalize
  11. Initialize
  12. 0
  13. Finalize
  14. Initialize
  15. Initialize
  16. -1
  17. Finalize
  18. Finalize
  19. Heap dump by heaptrc unit of "c:\Users\thadd\inlinetest.exe"
  20. 0 memory blocks allocated : 0
  21. 0 memory blocks freed     : 0
  22. 0 unfreed memory blocks : 0
  23. True heap size : 65536 (128 used in System startup)
  24. True free heap : 65408

There was a problem in the past, but fixed.
The "not initialized" warnings can be ignored.
« Last Edit: January 20, 2026, 02:27:55 pm by Thaddy »
If Europe sells their USA bonds the USD will collapse. Europe can affort that given average state debts. The USA can't affort that. Just an advice...

Okoba

  • Hero Member
  • *****
  • Posts: 648
Re: Default, Manual Initialize, or Automatic Initialize
« Reply #6 on: January 20, 2026, 02:33:54 pm »
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?

Khrys

  • Sr. Member
  • ****
  • Posts: 390
Re: Default, Manual Initialize, or Automatic Initialize
« Reply #7 on: January 20, 2026, 03:22:17 pm »
The following procedure...

Code: Pascal  [Select][+][-]
  1. procedure Foo();
  2. var
  3.   Bar: TManagedRecord;
  4. begin
  5.   WriteLn(Bar.A);
  6. end;

...is essentially the same as this:

Code: Pascal  [Select][+][-]
  1. procedure Foo();
  2. var
  3.   Bar: TManagedRecord_without_automatic_invocation_of_management_operators;
  4. begin
  5.   fpc_initialize(@Bar, TypeInfo(Bar));
  6.   try
  7.     WriteLn(Bar.A);
  8.   finally
  9.     fpc_finalize(@Bar, TypeInfo(Bar));
  10.   end;
  11. 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

  • Hero Member
  • *****
  • Posts: 648
Re: Default, Manual Initialize, or Automatic Initialize
« Reply #8 on: January 20, 2026, 03:39:42 pm »
"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

  • Full Member
  • ***
  • Posts: 117
Re: Default, Manual Initialize, or Automatic Initialize
« Reply #9 on: January 20, 2026, 03:41:57 pm »
Your original code works correctly in trunk but possibly not in 3.2.x:
Code: Text  [Select][+][-]
  1. Initialize
  2. Initialize
  3. -1
  4. Finalize
  5. Initialize
  6. -1
  7. Finalize
  8. Initialize
  9. -1
  10. Finalize
  11. Initialize
  12. 0
  13. Finalize
  14. Initialize
  15. Initialize
  16. -1
  17. Finalize
  18. Finalize
  19. Heap dump by heaptrc unit of "c:\Users\thadd\inlinetest.exe"
  20. 0 memory blocks allocated : 0
  21. 0 memory blocks freed     : 0
  22. 0 unfreed memory blocks : 0
  23. True heap size : 65536 (128 used in System startup)
  24. 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:

Quote
Initialize
-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
« Last Edit: January 20, 2026, 03:59:12 pm by LeP »

Okoba

  • Hero Member
  • *****
  • Posts: 648
Re: Default, Manual Initialize, or Automatic Initialize
« Reply #10 on: January 20, 2026, 07:25:07 pm »
That seems the correct output and behavior by the compiler.
Thank you for the test.

PascalDragon

  • Hero Member
  • *****
  • Posts: 6311
  • Compiler Developer
Re: Default, Manual Initialize, or Automatic Initialize
« Reply #11 on: January 20, 2026, 09:23:36 pm »
Seu 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

  • Hero Member
  • *****
  • Posts: 648
Re: Default, Manual Initialize, or Automatic Initialize
« Reply #12 on: January 20, 2026, 10:23:32 pm »
@PascalDragon here is your place to share your compiler knowledge please.

PascalDragon

  • Hero Member
  • *****
  • Posts: 6311
  • Compiler Developer
Re: Default, Manual Initialize, or Automatic Initialize
« Reply #13 on: January 20, 2026, 11:03:21 pm »
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. 🤷‍♀️

Khrys

  • Sr. Member
  • ****
  • Posts: 390
Re: Default, Manual Initialize, or Automatic Initialize
« Reply #14 on: January 21, 2026, 07:16:41 am »
"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.

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.

 

TinyPortal © 2005-2018