Recent

Author Topic: [NOT Solved] specialize TFPGObjectList<T>  (Read 1730 times)

BrunoK

  • Hero Member
  • *****
  • Posts: 589
  • Retired programmer
[NOT Solved] specialize TFPGObjectList<T>
« on: July 03, 2024, 12:21:56 pm »
Lazarus 3.99 (rev Unknown) FPC 3.2.2 x86_64-win64-win32/win64

In the following program
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. {$mode ObjFPC}{$H+}
  4.  
  5. uses
  6.   Classes,
  7.   SysUtils,
  8.   fgl;
  9.  
  10. const
  11.   cSymInvalid = low(integer);
  12.  
  13. type
  14.  
  15.   { TSymbolItem }
  16.  
  17.   TSymbolItem = class(TObject)
  18.   private
  19.     fSym: integer; {~bk}
  20.   public
  21.     procedure Clear;
  22.     property Sym: integer read fSym write fSym; {file position of symbol}
  23.   end; {TSymbolItem}
  24.  
  25.   { TSymbolBufferList - circular buffer list }
  26.  
  27.   TSymbolBufferList = class(specialize TFPGObjectList<TSymbolItem>)
  28.   private
  29.   const
  30.     cCap = 16;
  31.   private
  32.     FHead,              // Index offset of the oldest Symbol
  33.     FCurr,              //   "     "    of CurrentSymbol
  34.     FTail: integer;    // Index offset of the newest Symbol
  35.  
  36.     function LL0Get: TSymbolItem;
  37.     function LLGet(k: Integer): TSymbolItem;
  38.   protected
  39.   public
  40.     constructor Create;
  41.     procedure Clear;
  42.     property LL[k: Integer]: TSymbolItem read LLGet;
  43.     property LL0: TSymbolItem read LL0Get;
  44.   end;
  45.  
  46.   { TSymbolItem }
  47.  
  48.   procedure TSymbolItem.Clear;
  49.   begin
  50.     fSym := cSymInvalid;
  51.   end; { Clear }
  52.  
  53.   { TSymbolBufferList }
  54.  
  55.   constructor TSymbolBufferList.Create;
  56.   var
  57.     i: integer;
  58.     lNewSymPos: TSymbolItem;
  59.   begin
  60.     inherited;
  61.     // WriteLn(HexStr(List)); // Checked : .List has a valid pointer
  62.     for i := 0 to cCap - 1 do begin
  63.       lNewSymPos := TSymbolItem.Create;
  64.       lNewSymPos.Clear;
  65.       Add(lNewSymPos); // <<<<<<<<------------- ERROR HERE
  66.     end;
  67.   end;
  68.  
  69.   procedure TSymbolBufferList.Clear;
  70.   begin
  71.     FHead := 0;
  72.     FCurr := 0;
  73.     FTail := 0;
  74.   end;
  75.  
  76.   function TSymbolBufferList.LL0Get: TSymbolItem;
  77.   begin
  78.     if FTail = FCurr then
  79.       Exit(nil)
  80.     else
  81.       Exit(Items[FCurr]);
  82.   end;
  83.  
  84.   { Returns nil if no valid SymbolPosition for k }
  85.   function TSymbolBufferList.LLGet(k: Integer): TSymbolItem;
  86.   begin
  87.     { ... Code ... }
  88.   end;
  89.  
  90. var
  91.   vSymbolBufferList: TSymbolBufferList;
  92. begin
  93.   vSymbolBufferList := TSymbolBufferList.Create;
  94.   vSymbolBufferList.Free;
  95.   ReadLn;
  96. end.

I get :

Quote
Project project1 raised exception class 'External: ACCESS VIOLATION' with message:
Access violation writing to address $0000000000000000.

 In file 'fgl.pp' at line 1067

What is wrong in this little test program.
« Last Edit: July 03, 2024, 03:17:16 pm by BrunoK »

BrunoK

  • Hero Member
  • *****
  • Posts: 589
  • Retired programmer
Re: specialize TFPGObjectList<T>
« Reply #1 on: July 03, 2024, 12:37:13 pm »
This program compiles !

BrunoK

  • Hero Member
  • *****
  • Posts: 589
  • Retired programmer
Re: specialize TFPGObjectList<T>
« Reply #2 on: July 03, 2024, 01:00:47 pm »
Kind of bug in FPC, both 3.2.2 and trunk preparing a  PATCH.

BrunoK

  • Hero Member
  • *****
  • Posts: 589
  • Retired programmer
Re: specialize TFPGObjectList<T>
« Reply #3 on: July 03, 2024, 02:31:38 pm »
Solved, patch submitted to fpc GIT.

BrunoK

  • Hero Member
  • *****
  • Posts: 589
  • Retired programmer
Re: [Solved] specialize TFPGObjectList<T>
« Reply #4 on: July 03, 2024, 03:16:52 pm »
Sadly patch gives trouble due to compiler having difficulties knowing what constructor to call ....

BrunoK

  • Hero Member
  • *****
  • Posts: 589
  • Retired programmer
Re: [NOT Solved] specialize TFPGObjectList<T>
« Reply #5 on: July 03, 2024, 05:29:28 pm »
Simplified project
Code: Pascal  [Select][+][-]
  1. program pgmFgglTest;
  2.  
  3. {$mode ObjFPC}{$H+}
  4.  
  5. uses
  6.   Classes,
  7.   SysUtils,
  8.   fgl;
  9.  
  10. type
  11.  
  12.   { TSymbolBufferList - circular buffer list }
  13.  
  14.   TSymbolBufferList = class(specialize TFPGObjectList<TObject>)
  15.   private
  16.   const
  17.     cCap = 16; { The circular list of cached items }
  18.   private
  19.   protected
  20.   public
  21.     constructor Create;
  22.   end;
  23.  
  24.   { TSymbolBufferList }
  25.  
  26.   constructor TSymbolBufferList.Create;
  27.   var
  28.     i: integer;
  29.   begin
  30.     inherited  Create; { Compiles and runs OK }
  31.     // inherited; // Compiles but Fails at Runtime, apparently only calls
  32.                   //          TObject.Create but does not call AfterConstruction ? }
  33.     for i := 0 to cCap - 1 do
  34.       Add(nil); // <<<<<<<<------------- ERROR HERE
  35.   end;
  36.  
  37. var
  38.   vSymbolBufferList: TSymbolBufferList;
  39. begin
  40.   vSymbolBufferList := TSymbolBufferList.Create;
  41.   vSymbolBufferList.Free;
  42.   ReadLn;
  43. end.
I'am of the opinion that  line 31 inherited; should behave the same as line 30  inherited Create;

Some doc saying otherwise ?

jamie

  • Hero Member
  • *****
  • Posts: 6590
Re: [NOT Solved] specialize TFPGObjectList<T>
« Reply #6 on: July 03, 2024, 06:11:54 pm »
Try defining your class as "class" only. No tobject.
The only true wisdom is knowing you know nothing

Thaddy

  • Hero Member
  • *****
  • Posts: 15735
  • Censorship about opinions does not belong here.
Re: [NOT Solved] specialize TFPGObjectList<T>
« Reply #7 on: July 03, 2024, 06:21:21 pm »
No, that is wrong. Do not specialize to the root class (TObject) but to the class you actually mean to use: TfpgObectList has already the postfix modifier<T:class>.
What that means is that the list will only accept class instances (class) of type T.
What is so difficult to understand?
(btw: you are out of form, lately, Jamie   :-X :-[)
« Last Edit: July 03, 2024, 06:25:28 pm by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

Thaddy

  • Hero Member
  • *****
  • Posts: 15735
  • Censorship about opinions does not belong here.
Re: [NOT Solved] specialize TFPGObjectList<T>
« Reply #8 on: July 03, 2024, 06:31:29 pm »
@BrunoK
You can not add nil, because nil is untyped.
WHAT are you trying to achieve?
Maybe casting nil to Tobject will be accepted but is bad code: Add(TSomeObject(nil));
But I would reconsider my design first. Because class instances are pointers and you 'add' duplicates.(nil is a pointer type)
I don't think that is what you want? Describe it better.
Then I can explain it.
Are you maybe trying to create storage for uninitialized future instances? Then you are clueless.(and you are not a beginner)

Better description - not the code, but its purpose - leads to better help.
« Last Edit: July 03, 2024, 06:51:34 pm by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

jamie

  • Hero Member
  • *****
  • Posts: 6590
Re: [NOT Solved] specialize TFPGObjectList<T>
« Reply #9 on: July 03, 2024, 09:22:58 pm »
The "Inherited" call without a specified Create looks like it expects the inherited create to be the same, with no parameters.

Since there is no Constructor to override of the same parameters, I guess it's getting confused.

I bet it also gets confused in non-generic code, too.


The only true wisdom is knowing you know nothing

BrunoK

  • Hero Member
  • *****
  • Posts: 589
  • Retired programmer
Re: [NOT Solved] specialize TFPGObjectList<T>
« Reply #10 on: July 03, 2024, 10:18:47 pm »
No, that is wrong. Do not specialize to the root class (TObject) but to the class you actually mean to use: TfpgObectList has already the postfix modifier<T:class>.
What that means is that the list will only accept class instances (class) of type T.
What is so difficult to understand?
(btw: you are out of form, lately, Jamie   :-X :-[)
Generics are kind of macro for classes. The T is replaced by the TObject descendent class specifier (of course including TObject) specified in the specialization for the function.
Takes the specified class as replacement  for <T> and returns the specified class for function returning (in the generic class) without need to transtype.
I have frequently subclassed TFPObjectList .Get, Items etc (using helpers) to return the class that were stored in the list.

@BrunoK
You can not add nil, because nil is untyped.
Wrong nil is of type Pointer. TObject is Class(Pointer). Its definition is TObject = Pointer;

Quote
WHAT are you trying to achieve?
Maybe casting nil to Tobject will be accepted but is bad code: Add(TSomeObject(nil));
Why mess up with transtyping. You always can pass a descendant class to a function accepting a parent Class Type (but not the reverse). TObject descends from Pointer, nil is pointer.

Quote
But I would reconsider my design first. Because class instances are pointers and you 'add' duplicates.(nil is a pointer type)
I don't think that is what you want? Describe it better.
Of course my items are not just pointers, the example was the smallest that shows that inherited; is not compiled as inherited Create; as is generally accepted. I don't understand why so I ask.
TFPList and immediate descendants do not give shit about duplicates

Quote
Then I can explain it.
Are you maybe trying to create storage for uninitialized future instances? Then you are clueless.(and you are not a beginner)

Better description - not the code, but its purpose - leads to better help.
Implementation of a circular buffer using a TFPObjectList but using a generic (for convenience .... ha ha ha). Inheritance is so misunderstood in this community that you have TObjectList using a side FList: TFPList class to hold its items instead of simply subclassing TObjectList = class (TFPList) ... ridiculous but not dramatic.

BrunoK

  • Hero Member
  • *****
  • Posts: 589
  • Retired programmer
Re: [NOT Solved] specialize TFPGObjectList<T>
« Reply #11 on: July 03, 2024, 10:25:17 pm »
The "Inherited" call without a specified Create looks like it expects the inherited create to be the same, with no parameters.
That's what I always thought, but it seems to be different for generic derived types or with constructor that have default field values. It remains that AfterConstruction is no called in create when Inherited; alone is used, this I consider a BUG.

Quote
I bet it also gets confused in non-generic code, too.
Since there is no Constructor to override of the same parameters, I guess it's getting confused.
I dont' know, I'll try if I have time.

jamie

  • Hero Member
  • *****
  • Posts: 6590
Re: [NOT Solved] specialize TFPGObjectList<T>
« Reply #12 on: July 03, 2024, 11:00:05 pm »
May have something to do with the default Boolean in the inherited create. This could be a compiler problem, maybe but in any case, the compiler isn't warning you about possible conflicts.

  I believe the memory allocation for the class is first then a call to the constructor code and in this case, its blank and that never gets called, thus any code there never gets executed.

 Many things don't always have user code in the constructers.

P.S.
 Just took a deeper look, if you don't specify a "Create" (constructor), it never calls the actual code, if any.

  and I don't see a warning or suggestion about it in the log window, but I do see many "Inline inheritance not supported yet"
 
 Maybe that is interfering with the process.

 

« Last Edit: July 03, 2024, 11:35:21 pm by jamie »
The only true wisdom is knowing you know nothing

ASerge

  • Hero Member
  • *****
  • Posts: 2324
Re: [NOT Solved] specialize TFPGObjectList<T>
« Reply #13 on: July 04, 2024, 03:39:01 am »
That's what I always thought, but it seems to be different for generic derived types or with constructor that have default field values. It remains that AfterConstruction is no called in create when Inherited; alone is used, this I consider a BUG.
This is a bug. The inherited Create is not called, which sets the ItemSize to 8 bytes (TFPSList.Create) and it remains zero. As a result, the built-in FList storage is always nil and any attempts to copy to it are unsuccessful.

Thaddy

  • Hero Member
  • *****
  • Posts: 15735
  • Censorship about opinions does not belong here.
Re: [NOT Solved] specialize TFPGObjectList<T>
« Reply #14 on: July 04, 2024, 11:39:47 am »
Its definition is TObject = Pointer;
That doesn't say Pointer = TObject and that is what you assume. nil is really untyped.
The other way around makes a type, that is true, but then you need a cast: TObject(nil);
You have to tell the compiler that the untyped nil should be interpreted as TObject and not as any other pointer type. E.g., a Pchar can be nil but is not an object.

The mistake is that you think - by implication - nil is always a TObject and of course that is not true.

Should be clear.

Although I wonder if it should not be: TObject = type Pointer , because that would make your assumptions right.
« Last Edit: July 04, 2024, 12:04:24 pm by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

 

TinyPortal © 2005-2018