Lazarus

Free Pascal => General => Topic started by: Okoba on January 07, 2023, 08:13:04 am

Title: Questions about initialization
Post by: Okoba on January 07, 2023, 08:13:04 am
I have a couple of questions and confusions around initialization and I appreciate any help for clarifying them.

Question1:
I always faced this one, but never find out why.
Considering these two Tests:

Test1:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. var
  4.   A: array[0..10] of integer;
  5.   I: integer;
  6. begin
  7.   for I := 0 to High(A) do
  8.     WriteLn(A[I]);
  9.   ReadLn;
  10. end.

Test2:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3.   procedure Test;
  4.   var
  5.     A: array[0..10] of integer;
  6.     I: integer;
  7.   begin
  8.     for I := 0 to High(A) do
  9.       WriteLn(A[I]);
  10.   end;
  11.  
  12. begin
  13.   Test;
  14.   ReadLn;

Why in Test1, (as far as I know), A is zeroed, but not in Test2?
In both cases FPC warns about not initialized value.

Question2:
Why Initialize(A); does not zero the array?
Code: Pascal  [Select][+][-]
  1.   procedure Test;
  2.   var
  3.     A: array[0..10] of integer;
  4.     I: integer;
  5.   begin
  6.     Initialize(A);
  7.     for I := 0 to High(A) do
  8.       WriteLn(A[I]);
  9.   end;      
For example if I use Initialize on a record, it will zero any value in it, but not for arrays. And it is documented as "Initializing means zeroing out the memory area".
What is the logic behind this?
I guess, one can say, it does Initialize the memory of array, but not the induvial items, but the array in it self is a type, so why not Initializing (zeroing out) it too?

Question3:
And to add to confusion of myself, Initialize is documented as "In this sense it is close in functionality to Default, but Default requires an already initialized variable."
But if I try to do this, I will get a zeroed array, so they are not the same.

Code: Pascal  [Select][+][-]
  1.   procedure Test;
  2.   type
  3.     TA = array[0..10] of integer;
  4.   var
  5.     A: TA;
  6.     I: integer;
  7.   begin
  8.     A := Default(TA);
  9.     for I := 0 to High(A) do
  10.       WriteLn(A[I]);
  11.   end;  

Question4:
As said in documentation, "Default requires an already initialized variable." What does it mean? Is it best practice to call Initialize first and then Default?

Considering this sample:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3.   {$mode delphi}
  4. type
  5.  
  6.   { TTest }
  7.  
  8.   TTest = record
  9.     I: integer;
  10.     class operator Initialize(var AValue: TTest);
  11.     class operator Finalize(var AValue: TTest);
  12.     class operator AddRef(var AValue: TTest);
  13.     class operator Copy(constref A: TTest; var B: TTest);
  14.   end;
  15.  
  16.   class operator TTest.Initialize(var AValue: TTest);
  17.   begin
  18.     WriteLn('Initialize: ', QWord(@AValue));
  19.   end;
  20.  
  21.   class operator TTest.Finalize(var AValue: TTest);
  22.   begin
  23.     WriteLn('Finalize: ', QWord(@AValue));
  24.   end;
  25.  
  26.   class operator TTest.AddRef(var AValue: TTest);
  27.   begin
  28.     WriteLn('AddRef: ', QWord(@AValue));
  29.   end;
  30.  
  31.   class operator TTest.Copy(constref A: TTest; var B: TTest);
  32.   begin
  33.     WriteLn('Copy: ', QWord(@A), ' : ', QWord(@B));
  34.   end;
  35.  
  36.   procedure Test1;
  37.   var
  38.     V: TTest;
  39.   begin
  40.   end;
  41.  
  42.   procedure Test2;
  43.   var
  44.     V: TTest;
  45.   begin
  46.     Initialize(V);
  47.   end;
  48.  
  49.   procedure Test3;
  50.   var
  51.     V: TTest;
  52.   begin
  53.     V := Default(TTest);
  54.   end;
  55.  
  56. begin
  57.   WriteLn('Test1');
  58.   Test1; //No Initialize
  59.   WriteLn('Test2');
  60.   Test2; //Two Initialize on same pointer!
  61.   WriteLn('Test3');
  62.   Test3; //One Initialize
  63.   ReadLn;
  64.  
  65.   //Log:
  66.   //Test1
  67.   //Test2
  68.   //Initialize: 20971068
  69.   //Initialize: 20971068
  70.   //Finalize: 20971068
  71.   //Test3
  72.   //Initialize: 20971068
  73.   //Copy: 20971064 : 20971068
  74.   //Finalize: 20971068
  75. end.


Question5:
Why Test2 is initialize V two times for the same pointer?

Question6:
At Test3, Pointer 20971068 is initialized, but not 20971064. But FPC copies 20971064 to 20971068. Why? and how should I manage it to not duplicated a cost of copy? I thought Default, makes the value default, but it seem it makes a initialized(!) value and copy it to the variant.

Documentation of initialize: https://www.freepascal.org/docs-html/rtl/system/initialize.html


For future readers:
https://forum.lazarus.freepascal.org/index.php/topic,62706.msg474502.html#msg474502
Title: Re: Questions about initialization
Post by: speter on January 07, 2023, 08:30:38 am
Q1: I believe local variables are not initialised.
see https://www.freepascal.org/docs-html/ref/refse24.html

Q2: initialize() works on managed types, which I believe your array is not.
https://www.freepascal.org/docs-html/rtl/system/initialize.html

Q3: default() is the way to go :)

Q4: default's documentation (link below); does not say that default "requires an already initialized variable". I don't know why initialize's docs say that, it doesn't make any sense to me.
https://www.freepascal.org/docs-html/rtl/system/default.html


cheers
S.





Title: Re: Questions about initialization
Post by: howardpc on January 07, 2023, 09:02:15 am
The docs could have been more specific about Initialize and Finalize applying to managed variable types only.
For instance the pseudo signature could have been given as:
procedure Initialize(
  var T: TAnyManagedType;
  ACount: SizeInt (https://www.freepascal.org/docs-html/rtl/system/sizeint.html) = 1
);
Title: Re: Questions about initialization
Post by: Thaddy on January 07, 2023, 09:14:06 am
@4: fixed length arrays are an exception: you can call default() on it.
There is one caveat: you need to provide a type for the fixed length array.
E.g:
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$H+}{$ifdef mswindows}{$apptype console}{$endif}
  2. procedure test;
  3. type
  4.   TMyArray= array[0..9] of integer; // default() needs a type
  5. var
  6.   a:TMyArray;
  7.   i:integer;
  8. begin
  9.   for i in a do write(i,' ');writeln;// stack is dirty, array may contain random values
  10.   a:=Default(TMyArray); // clean the static array
  11.   writeln('===========================================');
  12.   for i in a do write(i,' ');writeln; //array contains only zero's
  13. end;
  14.  
  15. begin
  16.   test;
  17.   readln;
  18. end.

Example output (different for every run):
Code: [Select]
4194304 0 0 0 1 0 503 0 41120 1
===========================================
0 0 0 0 0 0 0 0 0 0

So the documentation for Initialize() is wrong.It should read: "an initialized variable or a type.".
As long there is a type, default will work happily.
Title: Re: Questions about initialization
Post by: MarkMLl on January 07, 2023, 09:56:53 am
Q1: I believe local variables are not initialised.
see https://www.freepascal.org/docs-html/ref/refse24.html

i.e. Local variables are on the stack, which is reused repeatedly hence might contain stale data.

Global variables might (depending on implementation details) be in a separate global space or might get the first bit of stack.

In the general case, it might be best not to assume that this is initialised: a great deal depends on the language implementation, the linker, and the behaviour of the OS when it allocates and loads initial memory.

MarkMLl
Title: Re: Questions about initialization
Post by: Thaddy on January 07, 2023, 10:42:37 am
i.e. Local variables are on the stack, which is reused repeatedly hence might contain stale data.

Global variables might (depending on implementation details) be in a separate global space or might get the first bit of stack.

In the general case, it might be best not to assume that this is initialised: a great deal depends on the language implementation, the linker, and the behaviour of the OS when it allocates and loads initial memory.

MarkMLl
Well,
1. stack allocations are almost always dirty, but there are exceptions, e.g. advanced records with an initialize operator.
2. with the default memory manager heap memory, globals are always initialized
3. when you use a different memory manager that may not be the case.
Title: Re: Questions about initialization
Post by: Okoba on January 07, 2023, 10:45:43 am
Thank you all for the help.
For now I consider Q1 as answered, thanks @MarkMLl. Maybe a hint in documentation helps future people, although FPC warning of not initialized value should be enough, but there will curious people like me for sure.

I still like to find better understating of Q2, Q3 and Q4, and based on the discussion I added Q5 and Q6 too.

I consider myself a newbie, but initialization seems more complicated than it should. I like to prevent calling Fill or FillZero on managed types as simply it is not "clean".
Pascal has strong typing system, calling memory functions on types seems, ugly and dangerous.
Title: Re: Questions about initialization
Post by: Thaddy on January 07, 2023, 11:01:10 am
Here's an example for advanced records even if allocated on the stack:
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$H+}{$ifdef mswindows}{$apptype console}{$endif}{$modeswitch advancedrecords}
  2. type
  3.   TMyRecord = record
  4.    a:array[0..9] of integer;
  5.    class operator initialize(var R:TMyRecord);
  6.   end;
  7.    
  8.    class operator TMyRecord.initialize(var R:TMyRecord);
  9.    var i:integer;
  10.    begin
  11.      R :=Default(TMyRecord);
  12.    end;
  13.    
  14. procedure test;  
  15. var
  16.   a:TMyRecord;  //implicit initialization even if on the stack.
  17.   i:integer;
  18. begin
  19.   for i in a.a do write(i,' ');writeln;// stack is dirty, but the record is initialized on declaration.
  20. end;
  21.  
  22. begin
  23.   test;
  24.   readln;
  25. end.
Title: Re: Questions about initialization
Post by: Okoba on January 07, 2023, 11:05:06 am
@Thaddy thanks for the sample.
So if I access the Record, it will be implicitly initialized. But compiler still warns me that it is not initialized, and if I try to add "Initialize(A);" it will initialize the record, two times, and it is not okay.
Title: Re: Questions about initialization
Post by: Thaddy on January 07, 2023, 11:17:37 am
My example should work out of the box without any warnings or errors.
You must have made a mistake, maybe a type somewhere? Maybe forgot the modeswitch? or maybe you compiled with -Sew? The latter is the only reason I can find that gives a compile time error, which is actually a compiler bug, but one that is not easy to fix....
You can fix my code like this to prevent this happening:
Code: Pascal  [Select][+][-]
  1. {$push}{$warn 5089 off}  
  2. procedure test;
  3. var
  4.   a:TMyRecord;  //implicit initialization even if on the stack.
  5.   i:integer;
  6.  begin
  7.   for i in a.a do write(i,' ');writeln;// stack is dirty, array may contain random values
  8. end;
  9. {$pop}
Title: Re: Questions about initialization
Post by: Okoba on January 07, 2023, 11:22:11 am
I attached an screenshot of your code, on today trunk version of Lazarus and FPC, that warns me about not initialized a.
Title: Re: Questions about initialization
Post by: Thaddy on January 07, 2023, 11:29:52 am
Look at my last reply, posts crossed. It is an overzealous compiler warning shown as error because you specified that. That is a bug, but not yours. By elimination the warning/error 5089 locally, the compiler won't give an error, nor a warning. In an ideal world this should be fixed, but there are bug reports for that issue and related (variables for which setlength() can be called) marked as won't fix.
Title: Re: Questions about initialization
Post by: Okoba on January 07, 2023, 12:14:12 pm
Do you have a link to such issue? Or know the reason of wont fix?
Title: Re: Questions about initialization
Post by: Thaddy on January 07, 2023, 12:52:29 pm
Do you have a link to such issue? Or know the reason of wont fix?
As far as I know, mostly from FPK, Jonas and PascalDragon, the reason is that it is simply too complex to fix and work-arounds exist.
You can search the bug tracker for "variable not initialized"
Too many entries to link to...
[EDIT]
Well, specify -OoDFA and the warning disappears....here... But only without -Sew.
Title: Re: Questions about initialization
Post by: PascalDragon on January 08, 2023, 04:23:44 pm
2. with the default memory manager heap memory, globals are always initialized
3. when you use a different memory manager that may not be the case.

Global variables are not initialized by the memory manager. They are initialized either by the OS as part of loading the binary or by the startup code in the executable. The memory manager has absolutely no knowledge about global variables.
Title: Re: Questions about initialization
Post by: Okoba on January 08, 2023, 04:29:15 pm
@PascalDragon, I would love to have your answers on the questions.
Title: Re: Questions about initialization
Post by: Thaddy on January 08, 2023, 07:57:12 pm
Me too....
Title: Re: Questions about initialization
Post by: PascalDragon on January 09, 2023, 09:30:14 pm
@PascalDragon, I would love to have your answers on the questions.

If there would have been anything significant to add to what speter wrote, I would have.
Title: Re: Questions about initialization
Post by: Thaddy on January 09, 2023, 10:03:04 pm
@PascalDragon

Well, for one, it is not the documentation for Default() that was incomplete, but the documentation for initialize(). Michael has picked up my report and eleborated a bit more in depth, so fixed it.
The reference comes from Initialize(), not Default().

Basically Default() can be used anywhere as long as there is a distinct type, not - only - an initialized variable.
And that was what the Initialize() entry stated, you may want to read Michael's corrections.
e.g. Default() will not take an array[0..99] of integer ad verbatum, but it will take it after you declare a type TMyFixedIntegerArrayZeroTo99 = array[0..99] of integer. That was the point. I consider it solved.
Btw my report also contains proof.
Title: Re: Questions about initialization
Post by: Okoba on January 10, 2023, 09:57:31 am
@PascalDragon what about Q5 and Q6?
Title: Re: Questions about initialization
Post by: Okoba on February 14, 2023, 10:06:15 am
I'm still confided about this subject. And adding to the conversation:
Question7:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3.   {$mode Delphi}
  4.  
  5. type
  6.   TTest = record
  7.     I: Integer;
  8.     class operator Initialize(var AValue: TTest);
  9.     class operator Finalize(var AValue: TTest);
  10.   end;
  11.  
  12.   class operator TTest.Initialize(var AValue: TTest);
  13.   begin
  14.     WriteLn('Initialize');
  15.     AValue.I := 0;
  16.   end;
  17.  
  18.   class operator TTest.Finalize(var AValue: TTest);
  19.   begin
  20.     WriteLn('Finalize');
  21.     AValue.I := 0;
  22.   end;
  23.  
  24.   procedure Test1;
  25.   var
  26.     V: TTest;
  27.   begin
  28.     //Initialize
  29.     WriteLn(V.I); //Warning: Local variable "V" of a managed type does not seem to be initialized
  30.     //Finalize
  31.   end;    
  32.  
  33. begin
  34.   Test1;
  35.   ReadLn;
  36. end.                        
  37.  

In this sample, I get warned by the compiler about not initialized variable, but the logs shows as it is initialized at procedure begin and finalized and the end.
So if the type is managed, and I added the Initialize and Finalize operators, and they are called automatically, why there is a warning?
And please keep in mind the Question6. I don't like Initializing the variant two types as it slows down the code and adds an extra copy, and sometimes makes the debugging process harder if you add a log.
Title: Re: Questions about initialization
Post by: Thaddy on February 14, 2023, 11:44:57 am
That warning is indeed pretty irritating and occurs with more constructs that do actually initialize, like setlength() too. There are already related bug reports for it, I believe.
Title: Re: Questions about initialization
Post by: PascalDragon on February 15, 2023, 11:01:18 pm
I personally agree that for local variables of managed types (not Result however) the “not initialized” warning/hint is not required. FPK however does not agree... 🤷‍♀️
Title: Re: Questions about initialization
Post by: Okoba on February 25, 2023, 01:27:20 pm
If the use didn't Initialize the value, eg V: Integer, I agree that the hint is required. But for a managed type that has Initialize operator, and FPC inserts code for Initialize, so it is clearly Initialized, then warning is redundant.
If there is a issue, I can check on that, or I can open one.
Title: Re: Questions about initialization
Post by: VisualLab on February 25, 2023, 03:50:57 pm
The docs could have been more specific about Initialize and Finalize applying to managed variable types only.
For instance the pseudo signature could have been given as:
procedure Initialize(
  var T: TAnyManagedType;
  ACount: SizeInt (https://www.freepascal.org/docs-html/rtl/system/sizeint.html) = 1
);

I support this proposal. I also suggest that you include a link to the documentation page that describes managed types in the description of this procedure. You should also complete the documentation page describing the Finalize procedure in the same way.

For comparison, I suggest looking at how it is described in the Delphi documentation: Initialize (https://docwiki.embarcadero.com/Libraries/Alexandria/en/System.Initialize), Finalize (https://docwiki.embarcadero.com/Libraries/Alexandria/en/System.Finalize). The description is a bit better (although it could be more detailed).

Unfortunately, there is also a flaw in the descriptions on these pages. If anyone has looked at the given pages of the Delphi documentation, they will have noticed that the documentation editor made mistakes at the beginning of both pages. Both procedures are overloaded. Identical copies are given in the references, which is misleading to people who do not have enough experience. Is:

Code: Pascal  [Select][+][-]
  1. procedure Initialize(var V; [ Count: NativeUInt]); overload;
  2. procedure Initialize(var V; [ Count: NativeUInt]); overload;
  3.  
  4. procedure Finalize(var V; [ Count: NativeUInt]); overload;
  5. procedure Finalize(var V; [ Count: NativeUInt]); overload;

And it should be:

Code: Pascal  [Select][+][-]
  1. procedure Initialize(var V); overload;
  2. procedure Initialize(var V; [ Count: NativeUInt]); overload;
  3.  
  4. procedure Finalize(var V); overload;
  5. procedure Finalize(var V; [ Count: NativeUInt]); overload;

On the other hand, inserting a link to a page that contains a list of procedures and functions that support memory management in the description deserves a plus: Dynamic Memory Allocation Routines (https://docwiki.embarcadero.com/RADStudio/Alexandria/en/Dynamic_Memory_Allocation_Routines).

Such information affects the understanding of the differences between Initialize and Default.

The name of the procedure: Default may also be a problem. It does not reflect well what its purpose is, i.e. fill the variable with zeros (probably even for those who speak English as their native language). Probably a better name for it would be to explicitly call it Zeroing. But now it probably can't be straightened out (using an alias?).

A page like this in the FPC documentation would be useful. Improving the documentation would greatly help people who are just starting to program in Pascal and Object Pascal using FPC (whether or not they have programmed anything before). I myself once had the understanding of how these subroutines work. Among other things, such trifles significantly affect the popularity of the language. And that's what we care about.
Title: Re: Questions about initialization
Post by: Thaddy on February 25, 2023, 04:25:27 pm
https://www.freepascal.org/docs-html/rtl/system/default.html
https://www.freepascal.org/docs-html/rtl/system/memoryfunctions.html

Note that default() can have serious side effects, just like in Delphi.

Title: Re: Questions about initialization
Post by: VisualLab on February 25, 2023, 04:37:32 pm
My post was only about suggestions to improve specific pages of the documentation (i.e. Initialize and Finalize). My mention of the Default function name was merely a digression (perhaps redundant).

As for the list of subroutines on the Memory management functions page (https://www.freepascal.org/docs-html/rtl/system/memoryfunctions.html), I don't see Initialize and Finalize on it. Why?
Title: Re: Questions about initialization
Post by: PascalDragon on February 25, 2023, 04:42:11 pm
If the use didn't Initialize the value, eg V: Integer, I agree that the hint is required. But for a managed type that has Initialize operator, and FPC inserts code for Initialize, so it is clearly Initialized, then warning is redundant.
If there is a issue, I can check on that, or I can open one.

There have been issues about this and FPK closed them as “won't fix”.

A page like this in the FPC documentation would be useful. Improving the documentation would greatly help people who are just starting to program in Pascal and Object Pascal using PFC (whether or not they have programmed anything before). I myself once had the understanding of how these subroutines work. Among other things, such trifles significantly affect the popularity of the language. And that's what we care about.

Then please report an issue for the documentation. It doesn't help if you say that things should be improved, the right people need to know about something being amiss.
Title: Re: Questions about initialization
Post by: Okoba on February 25, 2023, 04:50:31 pm
@PascalDragon That's unfortunate.
Thank you.
Title: Re: Questions about initialization
Post by: VisualLab on February 25, 2023, 04:59:20 pm
A page like this in the FPC documentation would be useful. Improving the documentation would greatly help people who are just starting to program in Pascal and Object Pascal using PFC (whether or not they have programmed anything before). I myself once had the understanding of how these subroutines work. Among other things, such trifles significantly affect the popularity of the language. And that's what we care about.

Then please report an issue for the documentation. It doesn't help if you say that things should be improved, the right people need to know about something being amiss.

OK. But where to report? (URL).
Title: Re: Questions about initialization
Post by: Okoba on February 25, 2023, 05:02:06 pm
https://gitlab.com/freepascal.org/fpc/documentation/-/issues
Title: Re: Questions about initialization
Post by: Blaazen on February 25, 2023, 05:10:12 pm
Fortunately, you can easily supress the messages "Variable "$1" of a managed type does not seem to be initialized" and keep it for non-managed types only.
BTW, why it's there twice - as a Hint and as a Warning? When I got hint and when I got warning?
Title: Re: Questions about initialization
Post by: Thaddy on February 25, 2023, 05:50:38 pm
It is in the left menu and called bugtracker.
https://gitlab.com/freepascal.org/fpc/source/-/issues

While your at it consult your eye specialist.. :o
Title: Re: Questions about initialization
Post by: VisualLab on February 25, 2023, 06:20:48 pm
It is in the left menu and called bugtracker.
https://gitlab.com/freepascal.org/fpc/source/-/issues

While your at it consult your eye specialist.. :o

I visited him in 2020 (it was after this visit that I bought glasses). This specialist then gave me medical advice: don't worry about people who haven't consulted their geriatric specialist :)
Title: Re: Questions about initialization
Post by: VisualLab on February 25, 2023, 06:46:45 pm
A page like this in the FPC documentation would be useful. Improving the documentation would greatly help people who are just starting to program in Pascal and Object Pascal using PFC (whether or not they have programmed anything before). I myself once had the understanding of how these subroutines work. Among other things, such trifles significantly affect the popularity of the language. And that's what we care about.

Then please report an issue for the documentation. It doesn't help if you say that things should be improved, the right people need to know about something being amiss.

Suggestion has been sent: A proposal to clarify the documentation of the procedures: Initialize and Finalize (https://gitlab.com/freepascal.org/fpc/documentation/-/issues/39338).

Title: Re: Questions about initialization
Post by: Thaddy on February 25, 2023, 07:55:18 pm
geriatric specialist :)
Yes I know I turned 65 this week, but average age according to my genes and family heritage is 90+  8-)
Anyway, thanks for the congratulations, I know you mean that!  :D

(nice one, tnx,  I know I deserve sarcastic)
Title: Re: Questions about initialization
Post by: VisualLab on February 25, 2023, 08:26:53 pm
...I turned 65 this week, but average age according to my genes and family heritage is 90+  8-)

This is good news for the participants of this forum. New users of Pascal who will ask in this forum, will need help from experienced programmers :D
Title: Re: Questions about initialization
Post by: Thaddy on February 25, 2023, 08:44:30 pm
If I could overflow on a nibble, I would be  zero :P ({R-} state required)
Title: Re: Questions about initialization
Post by: MarkMLl on February 25, 2023, 09:11:37 pm
Yes I know I turned 65 this week, but average age according to my genes and family heritage is 90+  8-)
Anyway, thanks for the congratulations, I know you mean that!  :D

Congratulations, but... youngster :-)

MarkMLl
TinyPortal © 2005-2018