Lazarus

Miscellaneous => Other => Topic started by: pda on July 11, 2017, 10:19:31 pm

Title: Automatic object deletion
Post by: pda on July 11, 2017, 10:19:31 pm
Hello. I still do not understand if it is possible to "advertise" myself. I made a small library that implements something kinde a smart pointers. A simple record that provides automatic removal of temporary objects when the function ends.

Instead of writing something like:
Code: Pascal  [Select][+][-]
  1. SomeObject1 := nil;
  2. SomeObject2 := nil;
  3. SomeObject3 := nil;
  4. try
  5.   SomeObject1 := TSomeObject1.Create;
  6.   SomeObject2 := TSomeObject2.Create;
  7.   SomeObject3 := TSomeObject3.Create;
  8.   <...>
  9. finally
  10.   SomeObject3.Free;
  11.   SomeObject2.Free;
  12.   SomeObject1.Free;
  13. end;

you can write like:

Code: Pascal  [Select][+][-]
  1. uses
  2.   AutoScope,<...>;
  3. <...>
  4. procedure SomeProc;
  5. var
  6.   Scoped: TScoped;
  7.   <...>
  8. begin
  9.   SomeObject1 := Scoped[TSomeObject1.Create] as TSomeObject1;
  10.   SomeObject2 := Scoped[TSomeObject2.Create] as TSomeObject2;
  11.   SomeObject3 := Scoped[TSomeObject3.Create] as TSomeObject3;
  12.   <...>
  13. end;

Compatible with Delphi 2007+ (may be with 2006+) and Free Pascal 2.6.0+. I'm interested in your opinion on this matter. I've heard fears that the compiler can delete a variable before it runs out of scope, just when it's no longer used. Although I could not find such behavior for the records.

https://github.com/pda0/AutoScope
Title: Re: Automatic object deletion
Post by: carl_caulkett on July 12, 2017, 12:10:36 am
Back in my Delphi 7 days, I did something similar with some code which relied on interfaces.

Code: Pascal  [Select][+][-]
  1. interface
  2.  
  3. type
  4.  
  5.   IcaAutoFree = interface
  6.   ['{FEC11200-4C4E-49D7-9F9F-C7178A687DA4}']
  7.     // Property methods
  8.     function GetInstance: Pointer;
  9.     // Properties
  10.     property Instance: Pointer read GetInstance;
  11.   end;
  12.  
  13.   TcaAutoFree = class(TInterfacedObject, IcaAutoFree)
  14.   private
  15.     // Private fields
  16.     FInstance: TObject;
  17.     // Property methods
  18.     function GetInstance: Pointer;
  19.   public
  20.     constructor Create(AInstance: TObject);
  21.     destructor Destroy; override;
  22.   end;
  23.  
  24. function Auto(AInstance: TObject): IcaAutoFree;
  25.  
  26. implementation
  27.  
  28. constructor TcaAutoFree.Create(AInstance: TObject);
  29. begin
  30.   inherited Create;
  31.   FInstance := AInstance;
  32. end;
  33.  
  34. destructor TcaAutoFree.Destroy;
  35. begin
  36.   FInstance.Free;
  37.   inherited;
  38. end;
  39.  
  40.   // Property methods
  41.  
  42. function TcaAutoFree.GetInstance: Pointer;
  43. begin
  44.   Result := FInstance;
  45. end;
  46.  
  47. function Auto(AInstance: TObject): IcaAutoFree;
  48. begin
  49.   Result := TcaAutoFree.Create(AInstance);
  50. end;
  51.  

Usage would be something along the lines of:

Code: Pascal  [Select][+][-]
  1. var
  2.   List: TStringList;
  3. begin
  4.   List := Auto(TStringList.Create).Instance;
  5.   // Do stuff with List...
  6.   // No need to free anything.
  7.   // Will automatically free contained object when interface goes out of scope. ie. at end of procedure/method.
  8.   // Copes with exceptions - no need for try finally
  9. end;
  10.  

The code was adapted from someone's code, but it was in use for several years in production code and never gave me any hassle whatsoever.
Title: Re: Automatic object deletion
Post by: taazz on July 12, 2017, 02:27:56 am
Hello. I still do not understand if it is possible to "advertise" myself.
there is the Announcement 3rd party group which is for this purpose.
I made a small library that implements something kinde a smart pointers. A simple record that provides automatic removal of temporary objects when the function ends.

Instead of writing something like:
Code: Pascal  [Select][+][-]
  1. SomeObject1 := nil;
  2. SomeObject2 := nil;
  3. SomeObject3 := nil;
  4. try
  5.   SomeObject1 := TSomeObject1.Create;
  6.   SomeObject2 := TSomeObject2.Create;
  7.   SomeObject3 := TSomeObject3.Create;
  8.   <...>
  9. finally
  10.   SomeObject3.Free;
  11.   SomeObject2.Free;
  12.   SomeObject1.Free;
  13. end;

you can write like:

Code: Pascal  [Select][+][-]
  1. uses
  2.   AutoScope,<...>;
  3. <...>
  4. procedure SomeProc;
  5. var
  6.   Scoped: TScoped;
  7.   <...>
  8. begin
  9.   SomeObject1 := Scoped[TSomeObject1.Create] as TSomeObject1;
  10.   SomeObject2 := Scoped[TSomeObject2.Create] as TSomeObject2;
  11.   SomeObject3 := Scoped[TSomeObject3.Create] as TSomeObject3;
  12.   <...>
  13. end;

I've heard fears that the compiler can delete a variable before it runs out of scope, just when it's no longer used. Although I could not find such behavior for the records.

https://github.com/pda0/AutoScope (https://github.com/pda0/AutoScope)
Yes there is a difference between delphi and FPC on how it handles unassigned interface variables, while delphi waits until the exit of the current procedure to clean up the stack and decrease the reference counter, fpc will decrease it the moment its not used any more and release it immediately. I haven't seen your library yet but if its interface based then it will not work.
Title: Re: Automatic object deletion
Post by: carl_caulkett on July 12, 2017, 06:46:12 am
That's interesting. I was afraid that may be the case. Indeed, since switching from Delphi to Lazarus, I've abandoned use of my Auto based construct after experiencing some issues that suggested that memory management had indeed changed.
Title: Re: Automatic object deletion
Post by: hnb on July 12, 2017, 08:47:44 am
Code: Pascal  [Select][+][-]
  1. var
  2.   List: TStringList;
  3. begin
  4.   List := Auto(TStringList.Create).Instance;
  5.   // Do stuff with List...
  6.   // No need to free anything.
  7.   // Will automatically free contained object when interface goes out of scope. ie. at end of procedure/method.
  8.   // Copes with exceptions - no need for try finally
  9. end;
  10.  
this code will not work in current FPC:

https://bugs.freepascal.org/view.php?id=26602
https://bugs.freepascal.org/view.php?id=30409
Title: Re: Automatic object deletion
Post by: Thaddy on July 12, 2017, 09:08:16 am
I already showed it works some time ago, Maciej... Ok, adapted example...: 8-) O:-)
Code: Pascal  [Select][+][-]
  1. program smartpointers;
  2. {$ifdef fpc}{$mode delphi}{$endif}
  3. uses
  4.   classes,smartptrs;
  5. var
  6.   L:TStringlist;
  7.   PL:Auto<TStringList>;
  8. begin
  9.   // Auto create
  10.   L:= PL.Value;
  11.   L.Add('Testme');
  12.   writeln(L.Count);
  13.   // Nothing
  14.   L:=PL.Value;
  15.   L.Add('foo');
  16.   L.Add('foo2');
  17.   L.Add('Foobar');
  18.   Writeln(L.Count);  
  19.   writeln(L.Text);
  20.   // Auto cleanup
  21. end.
Code: Pascal  [Select][+][-]
  1. unit smartptrs;
  2. {$ifdef fpc}{$mode delphi}{$endif}
  3. interface
  4. type
  5.   Auto<T:class, constructor> = record
  6.   strict private
  7.     FValue:T;
  8.     FFreeTheValue:IInterface;
  9.     function GetValue:T;
  10.     type
  11.       TFreeTheValue = class(TInterfacedObject)
  12.       private
  13.         fObjectToFree:TObject;
  14.       public
  15.         constructor Create(anObjectToFree: TObject);
  16.         destructor Destroy;override;
  17.       end;
  18.    public
  19.      constructor Create(AValue: T);overload;
  20.      procedure Create;overload;
  21.      class operator Implicit(AValue: T):Auto<T>;
  22.      class operator Implicit(smart: Auto<T>):T;
  23.     property value: T read GetValue;
  24.    end;
  25.  
  26. implementation
  27.    
  28.    constructor Auto<T>.TFreeTheValue.Create(anObjectToFree:TObject);
  29.    begin
  30.      self.fObjectToFree := anObjectToFree;
  31.    end;
  32.    
  33.    destructor Auto<T>.TFreeTheValue.Destroy;
  34.    begin
  35.      fObjectToFree.Free;
  36.      inherited;
  37.    end;
  38.    
  39.    constructor Auto<T>.Create(AValue:T);
  40.    begin
  41.      FValue := AValue;
  42.      FFreeTheValue := TFreeTheValue.Create(FValue);
  43.    end;
  44.    
  45.    procedure Auto<T>.Create;
  46.    begin
  47.      Auto<T>.Create(T.Create);
  48.    end;
  49.    
  50.    class operator Auto<t>.Implicit(AValue:T):Auto<T>;
  51.    begin
  52.      Result := Auto<T>.Create(AValue);
  53.    end;
  54.    
  55.    class operator Auto<T>.Implicit(smart: Auto<T>):T;
  56.    begin
  57.      Result := Smart.Value;
  58.    end;
  59.  
  60.    function Auto<T>.GetValue:T;
  61.    begin
  62.      if not Assigned(FFreeTheValue) then
  63.        Self := Auto<T>.Create(T.Create);
  64.      Result := FValue;
  65.    end;
  66. end.

It just needs some refinements  :D :D :D :D Up to you!
For average readers: Maciej is busy getting rid of the double declarations as I do in my code: it can be done at once. He is doing a great job.

In the mean time, my example gives a solution for the original question: automatic object deletion. It is already possible.
And before anyone behaves being stupid again, no this code does not leak! (compile with -glh)

Title: Re: Automatic object deletion
Post by: hnb on July 12, 2017, 09:28:34 am
I already showed it works some time ago, Maciej... Ok, adapted example...: 8-) O:-)

I mean the concrete example. When interface is returned as result of "Instance" function in Delphi is released at the end of function where "Instance" was called. In FPC the interface from "Instance" is released immediately. To fix differences between FPC and Delphi, the new switch SCOPED_INTERFACE_DESTROY would be not bad.
Title: Re: Automatic object deletion
Post by: Thaddy on July 12, 2017, 09:30:19 am
I already showed it works some time ago, Maciej... Ok, adapted example...: 8-) O:-)
the new switch SCOPED_INTERFACE_DESTROY would be not bad.
I agree. I am following your efforts as you now.
Title: Re: Automatic object deletion
Post by: Thaddy on July 12, 2017, 09:41:28 am
For the average readers:
We hope that:
Code: Pascal  [Select][+][-]
  1. var
  2.   L:TStringlist;
  3.   PL:Auto<TStringList>;

can be changed to:
Code: Pascal  [Select][+][-]
  1. var
  2.   L:Auto<TStringList>;

Or similar. Maciej is actively pursuing such syntax in the compiler.
I understand what he is doing, but can not do it myself.
It may be even possible to get rid of Auto altogether, by using a {$modeswitch ARC} or something, which would mean automatic object destruction would be guaranteed.

Title: Re: Automatic object deletion
Post by: Blestan on July 12, 2017, 09:45:18 am
and at least to be able to "mark" a type as for auto initialization / finalization when exiting a scoop


Title: Re: Automatic object deletion
Post by: Thaddy on July 12, 2017, 09:49:01 am
and at least to be able to "mark" a type as for auto initialization / finalization when exiting a scoop
Well, you can read my example code as doing just that: mark- by using the double declaration - .
As does Maciej's example with the use of auto.
But Maciej has a far more advanced concept in mind.
Note that your remark clutters the syntax. Memory management should be either/or all or nothing. IMHO.
Title: Re: Automatic object deletion
Post by: Blestan on July 12, 2017, 10:10:43 am
yes i know ... ARC i good but the bookkeeping can be broken very easy...
few years ago i was thinking if it possible to create local/nested memory managers depending on the context ... and when exiting a given context to free all memory
(i cannot explain it very well in english) but mozzila has some simiral aproach in some products. another solution (maybe i borrowed the idea from some texts) is to have all pointers to object initialized to null and examine the return stack and finalize all not used in return objects
Title: Re: Automatic object deletion
Post by: Thaddy on July 12, 2017, 10:19:37 am
yes i know ... ARC i good but the bookkeeping can be broken very easy...
In the case of what Maciej is trying to achieve: no, it can't.
In the case of my already working example: yes, it can.
That's why I am teasing Maciej.. :-\ (and you!)
Title: Re: Automatic object deletion
Post by: Blestan on July 12, 2017, 10:24:14 am
i read the whole communication of maciej with some of the core dev few months ago ... but i has left with the impression that there is some kind of resistentce ...

btw i have another question but will post a separate topic
Title: Re: Automatic object deletion
Post by: Thaddy on July 12, 2017, 10:32:40 am
i read the whole communication of maciej with some of the core dev few months ago ... but i has left with the impression that there is some kind of resistentce ...
Well, I read that too... Point is that devs are protectors of the language, almost all of them with a scientific qualification, and demand the highest standards (much higher than a commercial company demands).
Maciej is  aware of that, at some point wanted to give up, but now he is fully aware of the standards that are required. And he knows he is extremely respected by the core devs.

So maybe you interpreted the heavy discussions a bit wrong?

Simple Aristotle:
You only argue when you really care!
(I hope Maciej and devs agree that this is, just about, a proper summary)
Title: Re: Automatic object deletion
Post by: Blestan on July 12, 2017, 10:40:14 am
nooo im completely on maciej side ... just wondering about the resistance...
Title: Re: Automatic object deletion
Post by: Thaddy on July 12, 2017, 11:03:28 am
That's guardianship... Just that...That's why FPC turned into such a high quality compiler... nothing more, nothing less....
Title: Re: Automatic object deletion
Post by: carl_caulkett on July 12, 2017, 11:05:43 am
Code: Pascal  [Select][+][-]
  1. var
  2.   List: TStringList;
  3. begin
  4.   List := Auto(TStringList.Create).Instance;
  5.   // Do stuff with List...
  6.   // No need to free anything.
  7.   // Will automatically free contained object when interface goes out of scope. ie. at end of procedure/method.
  8.   // Copes with exceptions - no need for try finally
  9. end;
  10.  
this code will not work in current FPC:

https://bugs.freepascal.org/view.php?id=26602
https://bugs.freepascal.org/view.php?id=30409

Thanks for confirming this. It's a good job I don't use this anymore!
Title: Re: Automatic object deletion
Post by: Thaddy on July 12, 2017, 11:08:31 am
Why? because I just showed you it is possible already (with some quirks) and in the near future even easier?
Title: Re: Automatic object deletion
Post by: hnb on July 12, 2017, 11:11:52 am
...
(I hope Maciej and devs agree that this is, just about, a proper summary)
nooo im completely on maciej side ... just wondering about the resistance...
thanks :). Some resistance is sometimes good. It help to reflect (new ideas and roads) and help to keep humility, which is important in this kind of development. IMO a little lower resistance would be better
; )
Title: Re: Automatic object deletion
Post by: carl_caulkett on July 12, 2017, 11:24:45 am
Why? because I just showed you it is possible already (with some quirks) and in the near future even easier?

*Sigh*. When I said, "It's a good job I don't use this anymore!" I meant "it's a good job I don't use the code based on my IcaAutoFree/TcaAutoFree classes anymore".
Title: Re: Automatic object deletion
Post by: Thaddy on July 12, 2017, 11:36:32 am
*Sigh*. When I said, "It's a good job I don't use this anymore!" I meant "it's a good job I don't use the code based on my IcaAutoFree/TcaAutoFree classes anymore".
Thats' ok. I so overheated in this discussion I simply *know* you had to sigh after re-reading my own comments.,
But it was on topic. So I won't retract what I wrote, since it is still correct. Ok? :D
Title: Re: Automatic object deletion
Post by: carl_caulkett on July 12, 2017, 12:44:04 pm
No problem!

Can you clarify what you wrote earlier. As I understand it Maciej is working on an Auto mechanism which will be ready in a few months. But will this feature be limited to Delphi mode? And on a more general level what are the advantages and disadvantages of Delphi mode vs Objfpc mode. I have always used Objfpc mode because that's the default, and it seems to work fine for me. Would I gain any advantage by using Delphi mode?
Title: Re: Automatic object deletion
Post by: Thaddy on July 12, 2017, 12:58:26 pm
No problem!

Can you clarify what you wrote earlier. As I understand it Maciej is working on an Auto mechanism which will be ready in a few months.[ this is undefined. Time has no limits But will this feature be limited to Delphi mode? And on a more general level what are the advantages and disadvantages of Delphi mode vs Objfpc mode. I have always used Objfpc mode because that's the default, and it seems to work fine for me. Would I gain any advantage by using Delphi mode?
Apart from a slight edit in your remark:
Delphi mode?  Makes no difference. In OBJFPC mode type "specialize" (a lot) <grin>
FPC works on a per unit basis and the syntax you choose is based on what you prefer.... this is a concept that is amazing.... and not seen elsewhere on sourcecode level.
It is possible to use Delphi syntax in your own units (or><) without you ever knowing with what syntax the original code was written in a used unit.

So, if   when Maciej achieves what he wants it will be transparent. Like it is now.
Title: Re: Automatic object deletion
Post by: avra on July 12, 2017, 01:53:46 pm
this is a concept that is amazing.... and not seen elsewhere on sourcecode level.
+1  ;)
Title: Re: Automatic object deletion
Post by: carl_caulkett on July 12, 2017, 02:30:55 pm
Why? because I just showed you it is possible already (with some quirks) and in the near future even easier?

Thaddy, I must apologise, I didn't realise that the example code you posted showed that Auto free *is* possible now, albeit with the double declaration. When I first saw the message, I didn't look closely enough at the code. In my defence, I had just woken up! I'm going to try it out now.
Title: Re: Automatic object deletion
Post by: carl_caulkett on July 12, 2017, 02:51:33 pm
I already showed it works some time ago, Maciej... Ok, adapted example...: 8-) O:-)
Using Lazarus 1.8.0 RC3
macOS 10.12.5

I tried building a package with the unit, and when it tried to build the two lines:
Code: Pascal  [Select][+][-]
  1.    
  2.     class operator Implicit(AValue: T): Auto<T>;
  3.     class operator Implicit(Smart: Auto<T>): T;
  4.  


it fails with a couple of error messages which each say:
caauto.pas(27,48) Error: Impossible to overload assignment for equal types

Any ideas? Is this a typo? Should just one of those Implicit lines be in there?
Title: Re: Automatic object deletion
Post by: hnb on July 12, 2017, 03:28:44 pm
it fails with a couple of error messages which each say:
caauto.pas(27,48) Error: Impossible to overload assignment for equal types

Any ideas? Is this a typo? Should just one of those Implicit lines be in there?
you need to use latest FPC trunk. Lazarus is shipped with latest stable version of FPC.

related bug report: https://bugs.freepascal.org/view.php?id=30534

fixed in rev. 35740
Title: Re: Automatic object deletion
Post by: carl_caulkett on July 12, 2017, 05:37:13 pm
Thanks, Maciej. Presumably, if I were to build Lazarus using the latest FPC trunk, the IDE would not be so stable. Since I have a lot of code that I am involved in writing, at the moment, I think I will wait until a release version of Lazarus is released with these language changes included. I know it's a horrible question, but have you any idea when that might be? (When asked similar questions, I would always reply, "When it's ready"!)
Title: Re: Automatic object deletion
Post by: Thaddy on July 12, 2017, 05:56:20 pm
Carl, there is always a risk that something only works in trunk. Or does not work in a release.
I am sorry if some features we discussed here are not ready or back-ported to an official release.
It is also a demonstration of the care  that is taken before anything is allowed in the Language.
This is not a library change, no, it is on the language level. (And my  example was merely a demonstration of about year ago, with "Auto" search/replaced today)
Title: Re: Automatic object deletion
Post by: carl_caulkett on July 12, 2017, 06:36:08 pm
I quite understand Thaddy. I'm in no doubt about the amount of care taken by the Lazarus/FPC developers and the way that they endeavour to avoid releasing risky code just for the sake of it.

To be honest, I'm filled with the same sense of amazement when looking at the Lazarus/FPC source as I did when I first purchased the Delphi RAD pack in 1995 and got my hands on the VCL source code for the first time!
TinyPortal © 2005-2018