Vojtěch Čihák
2018-07-26 00:31:53 UTC
Hello,
Â
I needed to extend TFPGObjectList and I found two wierd things (FPC 3.1.1 r39507):
Â
program project1;
{$mode objfpc}{$H+}
Â
uses
 Classes, FGL;
Â
type
 TBaseClass = class (TObject)
 end;
Â
 TIDClass = class (TBaseClass)
  ID: Integer;
 end;
Â
 TNameIDClass = class (TIDClass)
  Name: string;
 end;
Â
 generic TFPGObjectListEx<T: TIDClass> = class (specialize TFPGObjectList<TBaseClass>) //1 A
  function GetItemByID(AID: Integer): T;
 end;
Â
 TNameIDList = class (specialize TFPGObjectListEx<TNameIDClass>)
Â
 end;
Â
{$R *.res}
Â
function TFPGObjectListEx.GetItemByID(AID: Integer): T;
begin
 {...}
 Result:=nil; //2
end;
Â
var NameIDList: TNameIDList;
  NameID: TNameIDClass;
begin
 NameID:=NameIDList.Items[0]; //1 B
end.
Â
The demo does not compile because of two errors:
1)Â project1.lpr(38,21) Error: Incompatible types: got "TBaseClass" expected "TNameIDClass" at comment //1 B
It is caused by declaration at //1 A. Class TFPGObjectListEx can be really generic only if it is declared like this:
  generic TFPGObjectListEx<T: TIDClass> = class (specialize TFPGObjectList<T>) //1 A, otherwise you must retype TNameIDClass(Items[0]) and it is against the philosophy of generics. Isn't it meaningless? Why there must be specialize to <T> when in fact it is no specialization at all.
Â
2)Â project1.lpr(32,11) Error: Incompatible types: got "Pointer" expected "$gendef4" at comment //2
The line must be changed to
  Result:=T(nil);
which seems bizarre to me, I've never seen retyping "nil". Even more, both TFPGObjectList and TFPGObjectListEx are constrained to TObject and to TIDClass so there is safety, TFPGObjectListEx can be only specialized with types that have "nil" (<T> can never be <Integer>, for example).
Â
Thanks,
Â
VojtÄch.
Â
PS: The demo crashes.
Â
I needed to extend TFPGObjectList and I found two wierd things (FPC 3.1.1 r39507):
Â
program project1;
{$mode objfpc}{$H+}
Â
uses
 Classes, FGL;
Â
type
 TBaseClass = class (TObject)
 end;
Â
 TIDClass = class (TBaseClass)
  ID: Integer;
 end;
Â
 TNameIDClass = class (TIDClass)
  Name: string;
 end;
Â
 generic TFPGObjectListEx<T: TIDClass> = class (specialize TFPGObjectList<TBaseClass>) //1 A
  function GetItemByID(AID: Integer): T;
 end;
Â
 TNameIDList = class (specialize TFPGObjectListEx<TNameIDClass>)
Â
 end;
Â
{$R *.res}
Â
function TFPGObjectListEx.GetItemByID(AID: Integer): T;
begin
 {...}
 Result:=nil; //2
end;
Â
var NameIDList: TNameIDList;
  NameID: TNameIDClass;
begin
 NameID:=NameIDList.Items[0]; //1 B
end.
Â
The demo does not compile because of two errors:
1)Â project1.lpr(38,21) Error: Incompatible types: got "TBaseClass" expected "TNameIDClass" at comment //1 B
It is caused by declaration at //1 A. Class TFPGObjectListEx can be really generic only if it is declared like this:
  generic TFPGObjectListEx<T: TIDClass> = class (specialize TFPGObjectList<T>) //1 A, otherwise you must retype TNameIDClass(Items[0]) and it is against the philosophy of generics. Isn't it meaningless? Why there must be specialize to <T> when in fact it is no specialization at all.
Â
2)Â project1.lpr(32,11) Error: Incompatible types: got "Pointer" expected "$gendef4" at comment //2
The line must be changed to
  Result:=T(nil);
which seems bizarre to me, I've never seen retyping "nil". Even more, both TFPGObjectList and TFPGObjectListEx are constrained to TObject and to TIDClass so there is safety, TFPGObjectListEx can be only specialized with types that have "nil" (<T> can never be <Integer>, for example).
Â
Thanks,
Â
VojtÄch.
Â
PS: The demo crashes.