Recent

Author Topic: Advanced Records Initialisation bug ?  (Read 669 times)

Nitorami

  • Sr. Member
  • ****
  • Posts: 427
Advanced Records Initialisation bug ?
« on: August 13, 2022, 10:15:53 am »
Advanced Records allow to define Class operators initialise/finalise to autoinitialise/clean up the record. That is very handy and spares extra calls to Create and Free as for Classes.

I used this for a random generator; the generator is a record and its state is autoinitialised. Works brillant when the record is global, also works when it is a Class field, BUT fails within a Class hierarchy. See below.
The generator rgen is a field of TSys0, and is correctly initilalised when creating an instance of TSys0, but NOT when creating an instance of TSys. Although TSys.Create calls TSys0.Create, rgen is not initialised.... have I misunderstood something ?

Attached the source files for testing. Sorry no Lazarus project, I am still used to work with the Textmode IDE. And I know the generator is crap, this is just for testing.
FPC3.2.2, win32, mode objfpc

Code: Pascal  [Select][+][-]
  1. uses randgen2;
  2.  
  3. type TSys0 = Class
  4.        rgen: TRandgen;
  5.        constructor create;
  6.        destructor destroy; override;
  7.      end;
  8.  
  9. constructor TSys0.Create;
  10. begin
  11.   writeln ('TSys0 now being created');
  12.   Inherited create;
  13.   writeln ('Print random numbers');
  14.   writeln (rgen.random32);
  15.   writeln (rgen.random32);
  16.   writeln (rgen.random32);
  17.   writeln (rgen.random32);
  18. end;
  19.  
  20. destructor TSys0.destroy;
  21. begin
  22.   inherited destroy;
  23. end;
  24.  
  25. //############################
  26.  
  27. type TSys = Class (TSys0)
  28.        constructor create;
  29.        destructor destroy; override;
  30.      end;
  31.  
  32. constructor TSys.Create;
  33. begin
  34.   Inherited create;
  35. end;
  36.  
  37. destructor TSys.destroy;
  38. begin
  39.   inherited destroy;
  40. end;
  41.  
  42. //############################
  43.  
  44. var C: TSys0;
  45.  
  46. begin
  47.   writeln;
  48.   writeln ('Create instance of TSys0...');
  49.   C := TSys0.Create;
  50.   C.Free;
  51.  
  52.   writeln;
  53.   writeln ('Create instance of TSys...');
  54.   C := TSys.Create;
  55.   C.Free;
  56. end.
  57.  

BrunoK

  • Sr. Member
  • ****
  • Posts: 349
  • Retired programmer
Re: Advanced Records Initialisation bug ?
« Reply #1 on: August 13, 2022, 02:53:11 pm »
Code: Pascal  [Select][+][-]
  1. type TSys = Class (TSys0)
  2.        // rgenB: TRandgen; // <-- comment / uncomment changes rgen initialize ~bk
  3.        constructor create;
  4.        destructor destroy; override;
  5.      end;
Modifying TSys fields gives strange result that depend on commenting/un-commenting rgenB.  Strange or did I make a mistake ?

ASerge

  • Hero Member
  • *****
  • Posts: 1985
Re: Advanced Records Initialisation bug ?
« Reply #2 on: August 14, 2022, 12:42:49 am »
Sorry no Lazarus project, I am still used to work with the Textmode IDE. And I know the generator is crap, this is just for testing.
FPC3.2.2, win32, mode objfpc
Bug reproduced. А simplified version that is also suitable for Delphi:
Code: Pascal  [Select][+][-]
  1. {$APPTYPE CONSOLE}
  2. {$IFDEF FPC}
  3.   {$MODE OBJFPC}
  4.   {$MODESWITCH ADVANCEDRECORDS}
  5. {$ENDIF}
  6.  
  7. type
  8.   TState = record
  9.   strict private
  10.     FState: LongWord;
  11.     class operator Initialize({$IFDEF FPC}var{$ELSE}out{$ENDIF} Instance: TState);
  12.   public
  13.     property State: LongWord read FState;
  14.   end;
  15.  
  16. class operator TState.Initialize({$IFDEF FPC}var{$ELSE}out{$ENDIF} Instance: TState);
  17. begin
  18.   Writeln('TState now being initialised');
  19.   Instance.FState := 1;
  20. end;
  21.  
  22. type
  23.   TSys0 = class(TObject)
  24.     FItem: TState;
  25.     constructor Create;
  26.   end;
  27.  
  28.   TSys = class(TSys0)
  29.     //FItem2: TState;
  30.   end;
  31.  
  32. constructor TSys0.Create;
  33. begin
  34.   inherited;
  35.   Writeln(ClassName + ' now being created');
  36.   Writeln('State=', FItem.State);
  37. end;
  38.  
  39. var
  40.   C: TSys;
  41. begin
  42.   Writeln('Create instance of TSys...');
  43.   C := TSys.Create;
  44.   C.Free;
  45.   Readln;
  46. end.
In FPC:
Quote
Create instance of TSys...
TSys now being created
State=0
In Delphi:
Quote
Create instance of TSys...
TState now being initialised
TSys now being created
State=1

PascalDragon

  • Hero Member
  • *****
  • Posts: 4556
  • Compiler Developer
Re: Advanced Records Initialisation bug ?
« Reply #3 on: August 14, 2022, 03:44:56 pm »
Fixed in 27c1bb3b. If no issues occur this will likely be merged to 3.2.3 as well.

Nitorami

  • Sr. Member
  • ****
  • Posts: 427
Re: Advanced Records Initialisation bug ?
« Reply #4 on: October 02, 2022, 04:34:10 pm »
Thanks for the fix.
I reopen this thread because I stumbled across a very similar issue: The same problem occurs when using an instance of an advanced record declared globally in another unit: The initalization is not called.

FPC 3.2.0, win32. Maybe the fix already solved that - sorry I cannot test because I don't understand gitlab.

Code: Pascal  [Select][+][-]
  1. unit testunit;
  2. {$MODE objfpc}
  3. {$MODESWITCH ADVANCEDRECORDS}
  4. INTERFACE
  5. type TGen = record
  6.               a: integer;
  7.               function content: integer;
  8.               class operator Initialize (var aRGen: TGen);
  9.               class operator Finalize   (var aRGen: TGen);
  10.             end;
  11.  
  12. var aGen: TGen;
  13.  
  14. IMPLEMENTATION
  15. function TGen.content: integer;
  16. begin
  17.   result := a;
  18. end;
  19.  
  20. class operator TGen.Initialize (var aRGen: TGen);
  21. begin
  22.   writeln ('init aRGen at address ',ptruint (@aRgen));
  23.   aRGen.a := 123456;
  24. end;
  25.  
  26. class operator TGen.Finalize   (var aRGen: TGen);
  27. begin
  28. end;
  29.  
  30. begin
  31. // initialize (aGen);  //without this, initialize is never called when using aGen from a different unit
  32. end.


Code: Pascal  [Select][+][-]
  1. uses testunit;
  2.  
  3. begin
  4.   writeln (aGen.content);  //prints zero
  5. end.

Arioch

  • Sr. Member
  • ****
  • Posts: 384
Re: Advanced Records Initialisation bug ?
« Reply #5 on: October 02, 2022, 05:54:09 pm »
Maybe the fix already solved that - sorry I cannot test because I don't understand gitlab.

You do not have to.

Provided your internet is fast and disk is large (and that is so for most desktops for last 10 years) you can just use FpcUpDeluxe.
There are caveats though. You have to make many copies of FpcUpDeluxe each manging their own copy of Lazarus.

So what i did recently:

1. I created a folder - d:\Lazarus.Edge\_UpdDx
2. I downloaded the win64 tool (there is win32 tool too) - d:\Lazarus.Edge\_UpdDx\fpcupdeluxe-x86_64-win64.exe
3. In the top left cornet i chnged "Set Install Dir" to D:\Lazarus.Edge
4. In the left "Basic" tab i set - this time - FPC and LAzarus versions to "trunk"  (old SVN term, that is Git is actually "master" or "main")
5. I went into "Setup+" down there to make both FPC and azarus be debug versions - but you probably won't need it. IF you only want to run your tests and see if they fail or succeed, you absolutely don't. But if you want to look into guts of FPC/LAz and hope to identiofy erros and suggest fixes - then you need debug builds.
6. I pressed Install FPC+Laz and went away

One hour later i went back and i had 3,5 GB folder with built FPC and Laz in them. Now i can run d:\Lazarus.Edge\lazarus\startlazarus.exe  and make my tests on bnleedign edhe

However, ii only very rarely do it. My main installation is

d:\fpcupdeluxe\lazarus\
d:\fpcupdeluxe\lazarus_deb\

Those are not "trunk" but "Fixes_2_2: and "Fixes_3_2" instead, they are managed by a different fpcupdeluxe copy too. They also have a number of my custom patches and git branching, etc, that you would not need, yet.

So, make your own folder like d:\Lazarus.stable and populate it like i described abouve, just with different branches (and no debug builds, but you do not need them in both versions anyway)

If to exclude the cloned debug-build nd -rd party libraries (CCR) that folder takes... 5GB. Wow. Guess there is some slack no one clears, maybe i should git gc more often



Arioch

  • Sr. Member
  • ****
  • Posts: 384
Re: Advanced Records Initialisation bug ?
« Reply #6 on: October 02, 2022, 05:58:31 pm »
Fixed in 27c1bb3b. If no issues occur this will likely be merged to 3.2.3 as well.

...and you want to implement BPLs...

One of the most delicious bugs in Delphi XE2 i met were exactly about implicit unit initializations, when the application consists of both statically linked and dynamically loaded BPLs ( plugins scheme );

And the manifestation was const Captions: array [xxx] of string = ( .... ) suddenly becoming empty strings.  I think they fixed it later in XE4 or XE6 but did not test.
It was one big wowser...

KodeZwerg

  • Sr. Member
  • ****
  • Posts: 306
  • Fifty shades of code.
    • Delphi & FreePascal
Re: Advanced Records Initialisation bug ?
« Reply #7 on: Today at 01:57:23 am »
The same problem occurs when using an instance of an advanced record declared globally in another unit: The initalization is not called.
From point of logic I would agree that such try needs to fail. It simple would make no sense. Imagine 10 units that include your super-record-unit, each change the value, who is correct?
Initialization should just local happen, this I try to say but I can not say if that is a rule.
« Last Edit: Tomorrow at 31:76:97 by KodeZwerg »

 

TinyPortal © 2005-2018