Recent

Author Topic: Houston we have a problem (with generics in trunk)  (Read 2086 times)

Thaddy

  • Hero Member
  • *****
  • Posts: 16170
  • Censorship about opinions does not belong here.
Houston we have a problem (with generics in trunk)
« on: June 19, 2024, 07:14:33 am »
This is probably a case of being blind to the issue, but it may also be a bug.
For some reason, the compiler doesn't allow me to add some generics to a unit, whereas the same generics work as expected when I declare them elsewhere.
The - working! - code is :
Code: Pascal  [Select][+][-]
  1. unit autofree experimental;
  2. {$if fpc_fullversion < 30301}
  3. {$error this code needs FPC version 3.3.1 or higher}
  4. {$ifend}
  5. {$mode delphi}{$interfaces com}
  6. {  
  7.   This code is inspired by the code from ASerge on the Freepascal forum.
  8.   I added a interface storage, which makes it possible to drop is and as
  9.   At the moment it has the disadvantage that all allocations are governed
  10.   by the store so all objects are released when the store is released.
  11.   I am working on that....}
  12.  
  13. interface
  14.  
  15. type
  16.   { Our own interface type }
  17.   IAutoFree = interface(IUnknown)
  18.   ['{89D8F215-61FF-4EBF-8C9E-9C027619DC0E}']
  19.   end;
  20.  
  21. { create an instance from a class reference }
  22. function Auto(ACls: TClass ): IAutoFree;overload;
  23. { create an instance of a class }
  24. function Auto(AObj: TObject): IAutoFree;overload;
  25. { Currently the compiler chokes on this:
  26. function Auto<T:class, constructor>:T;overload;
  27. procedure Auto<T:class>(out value:T);overload;}
  28. function AutoAdd(AObj: TObject): IAutoFree;overload;
  29.  
  30. implementation
  31.  
  32. uses
  33.   classes;
  34.    
  35. type  
  36.   TAutoFreeHolder = class(TInterfacedObject,IAutoFree)
  37.   strict private
  38.     FObj: TObject;
  39.   protected
  40.     function QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;winapi;
  41.   public
  42.     class var Store:IInterfaceList;
  43.     class constructor Create;
  44.     constructor Create(AObj: TObject);
  45.     destructor Destroy; override;
  46.   end;
  47.  
  48. { for some reason my current trunk version does not let me
  49.   add these two generics to the autofree unit
  50. function Auto<T:class, constructor>:T;overload;
  51. begin
  52.   Result := Auto(T.Create) as T;
  53. end;
  54.  
  55. procedure Auto<T:class>(out value:T);overload;
  56. begin
  57.   Value := Auto(T.Create) as T;
  58. end;
  59. }
  60.  
  61. function Auto(AObj: TObject): IAutoFree;overload;
  62. begin
  63.   Result := TAutoFreeHolder.Create(AObj);
  64.   TAutoFreeHolder.Store.Add(Result);
  65. end;
  66.  
  67. function Auto(ACls: TClass): IAutofree;overload;
  68. begin
  69.   Result := Auto(ACls.Create);
  70. end;
  71.  
  72. function AutoAdd(AObj: TObject): IAutofree;
  73. begin
  74.   Result := TAutoFreeHolder.Create(AObj);
  75. end;
  76.  
  77. class constructor TAutoFreeHolder.Create;
  78. begin
  79.   Store :=TInterfaceList.Create;
  80. end;
  81.  
  82. constructor TAutoFreeHolder.Create(AObj: TObject);
  83. begin
  84.   inherited Create;
  85.   FObj := AObj;
  86. end;
  87.  
  88. destructor TAutoFreeHolder.Destroy;
  89. begin
  90.   FObj.Free;
  91.   inherited;
  92. end;
  93.  
  94. function TAutoFreeHolder.QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;winapi;
  95. begin
  96.   if Assigned(FObj) and FObj.GetInterface(iid, obj) then
  97.     Result := S_OK
  98.   else
  99.     Result := inherited;
  100. end;
  101.  
  102. end.

And a - crude - demo looks like this:
Code: Pascal  [Select][+][-]
  1. program autoissue;
  2. {$mode delphi}{$apptype console}
  3. {$ifopt D+}{$assertions on}{$rangechecks on}{$endif}
  4. {$modeswitch implicitfunctionspecialization}
  5.  
  6. uses
  7.   classes,autofree;
  8. { for some reason my current trunk version does not let me
  9.   add these two generics to the autofree unit }
  10. function Auto<T:class, constructor>:T;overload;
  11. begin
  12.   Result := Auto(T.Create) as T;
  13. end;
  14.  
  15. procedure Auto<T:class>(out value:T);overload;
  16. begin
  17.   Value := Auto(T.Create) as T;
  18. end;
  19.  
  20. var
  21.   a,b,c:TStringlist;
  22.   d:TStringStream;
  23. begin
  24.   writeln('Creates a stringlist  as procedure and is auto free''d');
  25.   Auto(a);
  26.   a.Add('some');
  27.   writeln('content of a is: ',a.text);
  28.   writeln('creates a stringlist as a function and is auto free''d');
  29.   b:=Auto<TStringlist>;
  30.   b.Add('more');
  31.   writeln('content of b is: ',b.text);
  32.   writeln('add an existing instance to auto free');
  33.   c:=TStringlist.create;
  34.   autoAdd(c);
  35.   writeln('creates an auto free''d class from a paramererized created instance');
  36.   d := AutoAdd(TStringStream.Create(a.text+b.text+'This originates as a string stream')) as TStringStream;
  37.   writeln(d.datastring);
  38. end.

Why can't I add the two generic routines to the core unit?
Am I blind?

(please note this code makes heavy use of features that are ONLY available in trunk, if you do not use trunk, don't reply)

ASerge?, Benny?, PascalDragon?, Others?
« Last Edit: June 19, 2024, 10:24:44 am by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

avk

  • Hero Member
  • *****
  • Posts: 769
Re: houston we have a problem (with generics in trunk)
« Reply #1 on: June 19, 2024, 08:52:17 am »
It seems this?

Thaddy

  • Hero Member
  • *****
  • Posts: 16170
  • Censorship about opinions does not belong here.
Re: houston we have a problem (with generics in trunk)
« Reply #2 on: June 19, 2024, 09:06:45 am »
That may well be related, but does not fully explain why my code works if I define the two generic routines in a different scope. Thanks for thinking with me. Something to research if the issues are related. Gives me something to do  :D

I hate it when my code works, but do not - for the life of me - understand why it works or not.
Now I only know how it works - I designed it - and that it works.
But it is pushing the boundaries of the language, I know.
It is simple code, but deceivingly simple.

Your bug report doesn't mention scope. Will report back to you.

Again, thx for the pointer,

regards,

Thaddy
« Last Edit: June 19, 2024, 09:34:55 am by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

Thaddy

  • Hero Member
  • *****
  • Posts: 16170
  • Censorship about opinions does not belong here.
Re: Houston we have a problem (with generics in trunk)
« Reply #3 on: June 19, 2024, 11:42:24 am »
@avk,
Sorry I forgot you in the sum up. I should have known better. O:-)
If I smell bad code it usually is bad code and that includes my own code.

cdbc

  • Hero Member
  • *****
  • Posts: 1655
    • http://www.cdbc.dk
Re: Houston we have a problem (with generics in trunk)
« Reply #4 on: June 20, 2024, 08:31:42 pm »
Hi Thaddy
I get the following, when I try to compile your example:
Code: Bash  [Select][+][-]
  1. [bc@hp auto_intf]$ fpt.sh autoissue.lpr
  2. Free Pascal Compiler version 3.3.1-15019-g664f8fc2ba-dirty [2024/01/28] for x86_64
  3. Copyright (c) 1993-2024 by Florian Klaempfl and others
  4. Target OS: Linux for x86-64
  5. Compiling autoissue.lpr
  6. autoissue.lpr(7,11) Warning: Unit "autofree" is experimental
  7. autoissue.lpr(17,25) Error: Can't take the address of constant expressions
  8. autoissue.lpr(17,25) Error: Can't take the address of constant expressions
  9. autoissue.lpr(12,26) Error: Can't take the address of constant expressions
  10. autoissue.lpr(39) Fatal: There were 3 errors compiling module, stopping
  11. Fatal: Compilation aborted
  12. Error: /home/bc/laz_3/fpc/bin/x86_64-linux/ppcx64 returned an error exitcode
  13. [bc@hp auto_intf]$
The line in question is this:
Code: Pascal  [Select][+][-]
  1.   Value := Auto(T.Create) as T;
Could it be, that my /trunk/ is too old ?!?
Regards Benny
« Last Edit: June 20, 2024, 08:35:14 pm by cdbc »
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

Thaddy

  • Hero Member
  • *****
  • Posts: 16170
  • Censorship about opinions does not belong here.
Re: Houston we have a problem (with generics in trunk)
« Reply #5 on: June 21, 2024, 07:48:34 am »
That is maybe the case. I develop always with a trunk that is at most a week old.
Note that apart from the issue I described there are some more issues to be solved, not bugs perse but design flaws:
- The store holds the references during the lifetime of the store, usually application, too long!
- You can not call a manual free on the objects...yet...
To solve both issues at once I am writing a special tree that just like the store (IInterfaceList is based on TThreadList) is thread safe. You can then un-link the object when free'd.
This will solve both two other issues at the same time.
Only then the code is production ready, at the moment it is experimental.
A somewhat more descriptive example:
Code: Pascal  [Select][+][-]
  1. program testauto2;
  2. { describes the possibilities for autofree  }
  3. {$mode delphi}{$apptype console}
  4. {$ifopt D+}{$assertions on}{$rangechecks on}{$endif}
  5. {$modeswitch implicitfunctionspecialization}
  6. uses classes, autofree;
  7. { for some reason my current trunk version does not let me
  8.   add these two generics to the autofree unit }
  9. function Auto<T:class, constructor>:T;overload;
  10. begin
  11.   Result := Auto(T.Create) as T;
  12. end;
  13.  
  14. procedure Auto<T:class>(out value:T);overload;
  15. begin
  16.   Value := Auto(T.Create) as T;
  17. end;
  18.  
  19. var
  20.  a,b,c,d:Tstringlist;
  21. begin
  22.   { Direct on a variable }
  23.   auto(a);
  24.   { Through a specialization }
  25.   b := auto<Tstringlist>;
  26.   { Over an interface, basically ASerge's original idea }
  27.   c := auto(Tstringlist.create) as Tstringlist;
  28.   { Add  existing instance }
  29.   d := Tstringlist.create;
  30.   autoadd(d);
  31. end.
No leaks  :)

[edit]
by the way, your code that chokes is basically ASerge's code and that also works in 3.2.2.
« Last Edit: June 21, 2024, 11:59:56 am by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

cdbc

  • Hero Member
  • *****
  • Posts: 1655
    • http://www.cdbc.dk
Re: Houston we have a problem (with generics in trunk)
« Reply #6 on: June 21, 2024, 09:30:55 am »
Thanks Thaddy
I'll have a closer look, when I get the time ...every now and then, one has to 'run' the business, to keep it afloat, go figure...  :D
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

Thaddy

  • Hero Member
  • *****
  • Posts: 16170
  • Censorship about opinions does not belong here.
Re: Houston we have a problem (with generics in trunk)
« Reply #7 on: June 21, 2024, 09:48:20 am »
All I have to manage is a menageri of female species: wife, daughters, dogs and cat. O:-)
« Last Edit: June 21, 2024, 11:42:56 am by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

cdbc

  • Hero Member
  • *****
  • Posts: 1655
    • http://www.cdbc.dk
Re: Houston we have a problem (with generics in trunk)
« Reply #8 on: June 21, 2024, 10:01:28 am »
Hahaha... Thaddy, that mixture of yours, is enough to bring a good man to his knees  :D :o :D
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

 

TinyPortal © 2005-2018