A serious Memleak using delegates/implements (was: Delegate Interface class does not seem to be referenced counted)

classic Classic list List threaded Threaded
48 messages Options
123
Reply | Threaded
Open this post in threaded view
|

A serious Memleak using delegates/implements (was: Delegate Interface class does not seem to be referenced counted)

Marcos Douglas B. Santos
Hi,

Tony Whyman had posted on August 10 a problem with the compiler using Delegates.
He used a workaround to "solve" his problem and the thread died.

So, I coded a new example — more simpler, I think — to demonstrate the same problem and prove that there is some wrong that is causing a memleak.

=== BEGIN CODE ===

program Project1;

{$mode objfpc}{$H+}

uses
  Classes, SysUtils;

type
  IValue = interface
    function AsString: string;
  end;

  TIntegerValue = class(TInterfacedObject, IValue)
  private
    FValue: Integer;
  public
    constructor Create(Value: Integer);
    destructor Destroy; override;
    function AsString: string;
  end;

  TMyApp = class(TInterfacedObject, IValue)
  private
    FValue: IValue;
  public
    constructor Create(Value: Integer);
    destructor Destroy; override;
    property Value: IValue read FValue implements IValue;
  end;

{ TIntegerValue }

constructor TIntegerValue.Create(Value: Integer);
begin
  inherited Create;
  FValue := Value;
  WriteLn('TIntegerValue.Create');
end;

destructor TIntegerValue.Destroy;
begin
  WriteLn('TIntegerValue.Destroy');
  inherited Destroy;
end;

function TIntegerValue.AsString: string;
begin
  Result := 'Number is ' + IntToStr(FValue);
end;

{ TMyApp }

constructor TMyApp.Create(Value: Integer);
begin
  inherited Create;
  FValue := TIntegerValue.Create(Value);
  WriteLn('TMyApp.Create');
end;

destructor TMyApp.Destroy;
begin
  WriteLn('TMyApp.Destroy');
  inherited Destroy;
end;

// Program

procedure ExecuteIntegerValue;
var
  V: IValue;
begin
  WriteLn;
  WriteLn('IntegerValue:');
  V := TIntegerValue.Create(5);
  WriteLn(V.AsString);
end;

procedure ExecuteMyApp;
var
  App: TMyApp;
begin
  WriteLn;
  WriteLn('MyApp:');
  App := TMyApp.Create(10);
  try
    WriteLn(App.Value.AsString);
  finally
    App.Free;
  end;
end;

procedure ExecuteMyAppAsInterface;
var
  V: IValue;
begin
  WriteLn;
  WriteLn('MyAppAsInterface:');
  V := TMyApp.Create(20);
  WriteLn(V.AsString);
end;

begin
  ExecuteIntegerValue;
  ExecuteMyApp;
  ExecuteMyAppAsInterface;
  ReadLn;
end.

=== END CODE ===


Here is the output on my machine (Lazarus 1.7 r52880M FPC 3.0.1 i386-win32-win32/win64)


=== BEGIN OUTPUT ===

W:\temp>project1.exe

IntegerValue:
TIntegerValue.Create
Number is 5
TIntegerValue.Destroy

MyApp:
TIntegerValue.Create
TMyApp.Create
Number is 10
TMyApp.Destroy
TIntegerValue.Destroy

MyAppAsInterface:
TIntegerValue.Create
TMyApp.Create
Number is 20

Heap dump by heaptrc unit
83 memory blocks allocated : 2017/2200
81 memory blocks freed     : 1981/2160
2 unfreed memory blocks : 36
True heap size : 229376 (80 used in System startup)
True free heap : 229104
Should be : 229128
Call trace for block $01812928 size 20
  $004017DA  TMYAPP__CREATE,  line 59 of W:/temp/project1.lpr
  $00401B82  EXECUTEMYAPPASINTERFACE,  line 101 of W:/temp/project1.lpr
  $00401C08  main,  line 108 of W:/temp/project1.lpr
Call trace for block $018128C8 size 16
  $00401B82  EXECUTEMYAPPASINTERFACE,  line 101 of W:/temp/project1.lpr
  $00401C08  main,  line 108 of W:/temp/project1.lpr

W:\temp>

=== END OUTPUT ===


As you can see, the problem occurs just in the last test, when the classe TMyApp is used as an instance of the interface IValue.

I don't know if this problem was solved on trunk. I would like to know.
If not solved, I will open an issue.

Best regards,
Marcos Douglas

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A serious Memleak using delegates/implements (was: Delegate Interface class does not seem to be referenced counted)

Tony Whyman
On 05/10/16 16:26, Marcos Douglas wrote:
> Tony Whyman had posted on August 10 a problem with the compiler using
> Delegates.
> He used a workaround to "solve" his problem and the thread died.

Marcos,

I believe I concluded that this could be a bug or feature. Either way it
is a Bear Trap waiting for the unwary programmer and it would be nice if
in some way the implementation could be improved. The problem, as I see
it is:

Basics:

1. Whenever an interface reference is coerced from an interfaced object,
the object's reference count is incremented.

2. When the interface is copied that reference count is again incremented.

3. When the interface goes out of scope, the reference count is
decremented and when it reaches zero, the object is freed.

So far so good, but, when you have a delegated interface:

Terminalogy: In the example:

     TMyValue = class(TInterfacedObject,IValue);

     TMyObject = class (TinterfacedObject,IMyInterface)
     ...
     property Value: IValue read FValue implements IValue;
     end;

     Then a TMyValue object "is the source of" the delegated interface.
     A TMyObject object "provides" the delegated interface.

4. Whenever an interface reference to a delegated interfaced is coerced
from an interfaced object, it is the reference count of the object that
"is the source of" the delegated interface that is incremented.

5. When the interface is copied the reference count of the object that
"is the source of" the delegated interface is incremented.

6. When the interface goes out of scope, the reference count of the
object that "is the source of" the delegated interface is decremented
and when it reaches zero, that object is freed.

7. You are responsible for freeing the object that "provides" the
delegated interface.

To me this is counter-intuitive behaviour and this counter-intuitiveness
is compounded by the case where:

a. An interfaced object provides only a delegated interface.

b. An inherited interface (e.g. IUnknown) is coerced from the object.

In this case, the reference count incremented is that of the object that
"provides" the delegated interface  and not the object that "is the
source of" the delegated interface.

Where do we go from here?
======================

Provided you understand what is happening then it works - but there is
no real documentation and it is really easy to get this wrong.

For me the consistent approach should be that when you coerce an
interface from an object, the reference count of the object that
"provides" the delegated interface is always the one that is incremented
and the interface remains tied to that object  An object that "is the
source of" a delegated interface should always have its lifetime tied to
that of the object that "provides" the delegated interface. i.e. it has
an implicit reference to the object that is the source of the interface.

Tony Whyman
MWA

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A serious Memleak using delegates/implements (was: Delegate Interface class does not seem to be referenced counted)

Marcos Douglas B. Santos
Hi Tony,

On Wed, Oct 5, 2016 at 1:13 PM, Tony Whyman
<[hidden email]> wrote:
>
> [...]
>
> 7. You are responsible for freeing the object that "provides" the delegated
> interface.

But I'm working only using Interfaces. All variables are interfaces type.
So, I can't free the object myself.

> Where do we go from here?
> ======================
>
> Provided you understand what is happening then it works - but there is no
> real documentation and it is really easy to get this wrong.

I disagree.
Well, works, but with memleaks... so, I can't have a real program on
the server with memleaks.

> For me the consistent approach should be that when you coerce an interface
> from an object, the reference count of the object that "provides" the
> delegated interface is always the one that is incremented and the interface
> remains tied to that object  An object that "is the source of" a delegated
> interface should always have its lifetime tied to that of the object that
> "provides" the delegated interface. i.e. it has an implicit reference to the
> object that is the source of the interface.

I understood you but I can't help, because I don't know how the
compiler works to do this 'kind of magic' — I think only Object Pascal
has delegation in that way, right?

Delegates is a powerful feature. I can write less and compose complexy
objects using delegation. Really cool.

We need to compare with Delphi?
I don't have it, but I guess this problem there isn't there.

What do you think?

Best regards,
Marcos Douglas

On Wed, Oct 5, 2016 at 1:13 PM, Tony Whyman
<[hidden email]> wrote:

> On 05/10/16 16:26, Marcos Douglas wrote:
>>
>> Tony Whyman had posted on August 10 a problem with the compiler using
>> Delegates.
>> He used a workaround to "solve" his problem and the thread died.
>
>
> Marcos,
>
> I believe I concluded that this could be a bug or feature. Either way it is
> a Bear Trap waiting for the unwary programmer and it would be nice if in
> some way the implementation could be improved. The problem, as I see it is:
>
> Basics:
>
> 1. Whenever an interface reference is coerced from an interfaced object, the
> object's reference count is incremented.
>
> 2. When the interface is copied that reference count is again incremented.
>
> 3. When the interface goes out of scope, the reference count is decremented
> and when it reaches zero, the object is freed.
>
> So far so good, but, when you have a delegated interface:
>
> Terminalogy: In the example:
>
>     TMyValue = class(TInterfacedObject,IValue);
>
>     TMyObject = class (TinterfacedObject,IMyInterface)
>     ...
>     property Value: IValue read FValue implements IValue;
>     end;
>
>     Then a TMyValue object "is the source of" the delegated interface.
>     A TMyObject object "provides" the delegated interface.
>
> 4. Whenever an interface reference to a delegated interfaced is coerced from
> an interfaced object, it is the reference count of the object that "is the
> source of" the delegated interface that is incremented.
>
> 5. When the interface is copied the reference count of the object that "is
> the source of" the delegated interface is incremented.
>
> 6. When the interface goes out of scope, the reference count of the object
> that "is the source of" the delegated interface is decremented and when it
> reaches zero, that object is freed.
>
> 7. You are responsible for freeing the object that "provides" the delegated
> interface.
>
> To me this is counter-intuitive behaviour and this counter-intuitiveness is
> compounded by the case where:
>
> a. An interfaced object provides only a delegated interface.
>
> b. An inherited interface (e.g. IUnknown) is coerced from the object.
>
> In this case, the reference count incremented is that of the object that
> "provides" the delegated interface  and not the object that "is the source
> of" the delegated interface.
>
> Where do we go from here?
> ======================
>
> Provided you understand what is happening then it works - but there is no
> real documentation and it is really easy to get this wrong.
>
> For me the consistent approach should be that when you coerce an interface
> from an object, the reference count of the object that "provides" the
> delegated interface is always the one that is incremented and the interface
> remains tied to that object  An object that "is the source of" a delegated
> interface should always have its lifetime tied to that of the object that
> "provides" the delegated interface. i.e. it has an implicit reference to the
> object that is the source of the interface.
>
> Tony Whyman
> MWA
>
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A serious Memleak using delegates/implements (was: Delegate Interface class does not seem to be referenced counted)

Graeme Geldenhuys-6
In reply to this post by Marcos Douglas B. Santos
On 2016-10-05 16:26, Marcos Douglas wrote:
> Here is the output on my machine (Lazarus 1.7 r52880M FPC 3.0.1
> i386-win32-win32/win64)

Just so you know... bug or not, it seems to have the same behaviour as
with Delphi 7. Compiled with D7 it has the exact same output. In fact,
compiled with Delphi 7, the app doesn't quit at all. I had to Ctrl+C it.


========================================================
c:\Programming\test\interface_delegation_delphi>project1.exe

IntegerValue:
TIntegerValue.Create
Number is 5
TIntegerValue.Destroy

MyApp:
TIntegerValue.Create
TMyApp.Create
Number is 10
TMyApp.Destroy
TIntegerValue.Destroy

MyAppAsInterface:
TIntegerValue.Create
TMyApp.Create
Number is 20
^C
c:\Programming\test\interface_delegation_delphi>

========================================================

Regards,
  Graeme

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A serious Memleak using delegates/implements (was: Delegate Interface class does not seem to be referenced counted)

Graeme Geldenhuys-6
On 2016-10-05 22:51, Graeme Geldenhuys wrote:
> In fact,
> compiled with Delphi 7, the app doesn't quit at all. I had to Ctrl+C it.


Ignore that bit... Looking at the code in detail I see there was a
ReadLn statement at the end. Dope! :)


Regards,
  Graeme

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A serious Memleak using delegates/implements (was: Delegate Interface class does not seem to be referenced counted)

Graeme Geldenhuys-6
In reply to this post by Marcos Douglas B. Santos
On 2016-10-05 16:26, Marcos Douglas wrote:
> So, I coded a new example — more simpler, I think — to demonstrate the same
> problem and prove that there is some wrong that is causing a memleak.

Martin Schreiber recently mentioned in another Interface discussion that
there is a very good reason he doesn’t use COM style interfaces…
Reference Counting!

Stick with CORBA style interfaces and things work much simpler. I have
to agree. I’ve used CORBA style interfaces for years with great success
and no memory leaks. You get all the benefits of Interfaces, but without
the Reference Counting troubles and complexities. If you really are
writing COM (Windows specific) applications, then fine — otherwise use
CORBA style interfaces.

Just my 2¢ worth.

Regards,
  Graeme

--
fpGUI Toolkit — a cross-platform GUI toolkit using Free Pascal
http://fpgui.sourceforge.net/

My public PGP key:  http://tinyurl.com/graeme-pgp
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A serious Memleak using delegates/implements (was: Delegate Interface class does not seem to be referenced counted)

Tony Whyman
In reply to this post by Marcos Douglas B. Santos

On 05/10/16 19:19, Marcos Douglas wrote:

> Hi Tony,
>
> On Wed, Oct 5, 2016 at 1:13 PM, Tony Whyman
> <[hidden email]> wrote:
>> [...]
>>
>> 7. You are responsible for freeing the object that "provides" the delegated
>> interface.
> But I'm working only using Interfaces. All variables are interfaces type.
> So, I can't free the object myself.
As I understand it, it depends on the variable to which the object is
first assigned. For example:

TMyClass = class(TInterfacedObject,IUnknown);

var Obj: TMyClass; {Note the var is of type TMyClass}
begin
   Obj := TMyClass.Create;
   try
    ...
   finally
     Obj.Free; {This is OK and necessary}
   end
end;

Alternatively:

var Obj: IUnknown;
begin
   Obj := TMyClass.Create;
   try
    ...
   finally
     Obj.Free; {Not required and will cause an exception when obj goes
out of scope}
   end
end;

>> Where do we go from here?
>> ======================
>>
>> Provided you understand what is happening then it works - but there is no
>> real documentation and it is really easy to get this wrong.
> I disagree.
> Well, works, but with memleaks... so, I can't have a real program on
> the server with memleaks.
No, if you explicitly free the provider class there will be no memleaks.
My point is that having to do this is counter-intuitive and  easy to get
wrong - or to overlook cases where it is necessary.

>
>> For me the consistent approach should be that when you coerce an interface
>> from an object, the reference count of the object that "provides" the
>> delegated interface is always the one that is incremented and the interface
>> remains tied to that object  An object that "is the source of" a delegated
>> interface should always have its lifetime tied to that of the object that
>> "provides" the delegated interface. i.e. it has an implicit reference to the
>> object that is the source of the interface.
> I understood you but I can't help, because I don't know how the
> compiler works to do this 'kind of magic' — I think only Object Pascal
> has delegation in that way, right?
Here I was suggesting a compiler change (bug fix?)
>
> Delegates is a powerful feature. I can write less and compose complexy
> objects using delegation. Really cool.
>
> We need to compare with Delphi?
> I don't have it, but I guess this problem there isn't there.
I never used delegated interfaces in Delphi. In FPC I try to avoid them
given the problems you get. On the other hand, reference counted com
interfaces are a great feature and it's a pity delegated interfaces are
so awkward.

>
> What do you think?
>
> Best regards,
> Marcos Douglas
>
> On Wed, Oct 5, 2016 at 1:13 PM, Tony Whyman
> <[hidden email]> wrote:
>> On 05/10/16 16:26, Marcos Douglas wrote:
>>> Tony Whyman had posted on August 10 a problem with the compiler using
>>> Delegates.
>>> He used a workaround to "solve" his problem and the thread died.
>>
>> Marcos,
>>
>> I believe I concluded that this could be a bug or feature. Either way it is
>> a Bear Trap waiting for the unwary programmer and it would be nice if in
>> some way the implementation could be improved. The problem, as I see it is:
>>
>> Basics:
>>
>> 1. Whenever an interface reference is coerced from an interfaced object, the
>> object's reference count is incremented.
>>
>> 2. When the interface is copied that reference count is again incremented.
>>
>> 3. When the interface goes out of scope, the reference count is decremented
>> and when it reaches zero, the object is freed.
>>
>> So far so good, but, when you have a delegated interface:
>>
>> Terminalogy: In the example:
>>
>>      TMyValue = class(TInterfacedObject,IValue);
>>
>>      TMyObject = class (TinterfacedObject,IMyInterface)
>>      ...
>>      property Value: IValue read FValue implements IValue;
>>      end;
>>
>>      Then a TMyValue object "is the source of" the delegated interface.
>>      A TMyObject object "provides" the delegated interface.
>>
>> 4. Whenever an interface reference to a delegated interfaced is coerced from
>> an interfaced object, it is the reference count of the object that "is the
>> source of" the delegated interface that is incremented.
>>
>> 5. When the interface is copied the reference count of the object that "is
>> the source of" the delegated interface is incremented.
>>
>> 6. When the interface goes out of scope, the reference count of the object
>> that "is the source of" the delegated interface is decremented and when it
>> reaches zero, that object is freed.
>>
>> 7. You are responsible for freeing the object that "provides" the delegated
>> interface.
>>
>> To me this is counter-intuitive behaviour and this counter-intuitiveness is
>> compounded by the case where:
>>
>> a. An interfaced object provides only a delegated interface.
>>
>> b. An inherited interface (e.g. IUnknown) is coerced from the object.
>>
>> In this case, the reference count incremented is that of the object that
>> "provides" the delegated interface  and not the object that "is the source
>> of" the delegated interface.
>>
>> Where do we go from here?
>> ======================
>>
>> Provided you understand what is happening then it works - but there is no
>> real documentation and it is really easy to get this wrong.
>>
>> For me the consistent approach should be that when you coerce an interface
>> from an object, the reference count of the object that "provides" the
>> delegated interface is always the one that is incremented and the interface
>> remains tied to that object  An object that "is the source of" a delegated
>> interface should always have its lifetime tied to that of the object that
>> "provides" the delegated interface. i.e. it has an implicit reference to the
>> object that is the source of the interface.
>>
>> Tony Whyman
>> MWA
>>
> _______________________________________________
> fpc-pascal maillist  -  [hidden email]
> http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
>

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A serious Memleak using delegates/implements (was: Delegate Interface class does not seem to be referenced counted)

Tony Whyman
In reply to this post by Graeme Geldenhuys-6
On 05/10/16 23:03, Graeme Geldenhuys wrote:
> Martin Schreiber recently mentioned in another Interface discussion that
> there is a very good reason he doesn’t use COM style interfaces…
> Reference Counting!
Used properly reference counted interfaces are very powerful and allow
for some very elegant programming. Do you complain about AnsiStrings?
They are reference counted. Would you really want to have to free every
string explicitly? Dynamic arrays are similarly reference counted.

Reference counted interfaces allow you to create classes (and objects)
that behave in the same way as AnsiStrings. IMHO, a lot of standard
packages would be greatly improved if they used com interfaces.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A serious Memleak using delegates/implements (was: Delegate Interface class does not seem to be referenced counted)

Marcos Douglas B. Santos
In reply to this post by Graeme Geldenhuys-6
On Wed, Oct 5, 2016 at 6:51 PM, Graeme Geldenhuys
<[hidden email]> wrote:

> On 2016-10-05 16:26, Marcos Douglas wrote:
>> Here is the output on my machine (Lazarus 1.7 r52880M FPC 3.0.1
>> i386-win32-win32/win64)
>
> Just so you know... bug or not, it seems to have the same behaviour as
> with Delphi 7. Compiled with D7 it has the exact same output. In fact,
> compiled with Delphi 7, the app doesn't quit at all. I had to Ctrl+C it.
> [...]
> Ignore that bit... Looking at the code in detail I see there was a
> ReadLn statement at the end. Dope! :)

But, the result was the same, even using D7.
So, is this by design? Sad...

Regards,
Marcos Douglas
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A serious Memleak using delegates/implements (was: Delegate Interface class does not seem to be referenced counted)

Marcos Douglas B. Santos
In reply to this post by Graeme Geldenhuys-6
On Wed, Oct 5, 2016 at 7:03 PM, Graeme Geldenhuys
<[hidden email]> wrote:
> Martin Schreiber recently mentioned in another Interface discussion that
> there is a very good reason he doesn’t use COM style interfaces…
> Reference Counting!

I understand you, but reference counting help us to write a better
code, more object-oriented.

> Stick with CORBA style interfaces and things work much simpler. I have
> to agree. I’ve used CORBA style interfaces for years with great success
> and no memory leaks. You get all the benefits of Interfaces, but without
> the Reference Counting troubles and complexities. If you really are
> writing COM (Windows specific) applications, then fine — otherwise use
> CORBA style interfaces.

Simplicity. I think that's depends on point of view.
Today I write a better code than 3~4 years ago. For me it's much more simpler:
- no more .Free
- no more try-finally (to use .Free)
- no inheritance
- less variables and types declarations
- more functional design

I'm using decorator pattern. No problem with it, but delegates makes
me write less code and the design is awesome. None language has the
same feature, as far as I know. We have it, but doesn't work... well,
doesn't work in all cases, in all possibilities.

For me, it's a bug. Sorry.

Best regards,
Marcos Douglas
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A serious Memleak using delegates/implements (was: Delegate Interface class does not seem to be referenced counted)

Marcos Douglas B. Santos
In reply to this post by Tony Whyman
On Wed, Oct 5, 2016 at 7:07 PM, Tony Whyman
<[hidden email]> wrote:
>
>[...]
>
> No, if you explicitly free the provider class there will be no memleaks. My
> point is that having to do this is counter-intuitive and  easy to get wrong
> - or to overlook cases where it is necessary.

That is it, counter-intuitive and  easy to get wrong.

Another thing easily to forget and get memleaks is not get the result
of constructors.
For example. Consider this:

function TFoo.Execute(const Name: string): string;
begin
  Result := TAction.Create(TTask.Create(Name)).Execute.ToString;
end;

- TTask is a class that takes a string in the constructor;
- TTask implements ITask, an interface;
- TAction is a class that receives an ITask interface in the constructor;
- TAction implements IAction, an interface;
- TAction has an Execute method that returns an IResult, an interface;
- IResult has a ToString method that returns the result in string format;

How many memory leaks we have here? 0, 1 or 2?
The answer is 1.

So, we need to declare an variable:

function TFoo.Execute(const Name: string): string;
var
  A: IAction;
begin
  A := TAction.Create(TTask.Create(Name));
  Result := A.Execute.ToString;
end;

Verbose and unnecessary, in my opinion.
Sometimes I forget to declare a variable, sometimes not... this is unproductive!

So, I created my own "design pattern" that I called: New Method.

The refactored code is:

function TFoo.Execute(const Name: string): string;
begin
  Result := TAction.New(TTask.New(Name)).Execute.ToString;
end;

I explained here
http://objectpascalprogramming.com/posts/interfaces-e-o-metodo-estatico-new/
but you need to translate.

>> I understood you but I can't help, because I don't know how the
>> compiler works to do this 'kind of magic' — I think only Object Pascal
>> has delegation in that way, right?
>
> Here I was suggesting a compiler change (bug fix?)

+1

>> Delegates is a powerful feature. I can write less and compose complexy
>> objects using delegation. Really cool.
>>
>> We need to compare with Delphi?
>> I don't have it, but I guess this problem there isn't there.
>
> I never used delegated interfaces in Delphi. In FPC I try to avoid them
> given the problems you get. On the other hand, reference counted com
> interfaces are a great feature and it's a pity delegated interfaces are so
> awkward.

I agree.

Best regards,
Marcos Douglas
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A serious Memleak using delegates/implements (was: Delegate Interface class does not seem to be referenced counted)

Marcos Douglas B. Santos
In reply to this post by Tony Whyman
On Wed, Oct 5, 2016 at 7:16 PM, Tony Whyman
<[hidden email]> wrote:
>
> Reference counted interfaces allow you to create classes (and objects) that
> behave in the same way as AnsiStrings. IMHO, a lot of standard packages
> would be greatly improved if they used com interfaces.

I agree with you 100%.

Best regards,
Marcos Douglas
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A serious Memleak using delegates/implements (was: Delegate Interface class does not seem to be referenced counted)

Martin Schreiber-2
In reply to this post by Tony Whyman
On Thursday 06 October 2016 00:16:22 Tony Whyman wrote:

> On 05/10/16 23:03, Graeme Geldenhuys wrote:
> > Martin Schreiber recently mentioned in another Interface discussion that
> > there is a very good reason he doesn’t use COM style interfaces…
> > Reference Counting!
>
> Used properly reference counted interfaces are very powerful and allow
> for some very elegant programming. Do you complain about AnsiStrings?
> They are reference counted. Would you really want to have to free every
> string explicitly? Dynamic arrays are similarly reference counted.
>
Reference counting is great for simple types like strings and dynamic arrays
but is a nightmare with the venturesome mixture of COM-interface and classes
from Delphi. Even reference counting for complex classes is no good idea IMO,
I fear the times when FPC will implement ARC.
I don't think that a programming language should hide more and more of the
internal working of the code he writes from the programmer. Take a look at
the modern C++ programs; the LLVM-compiler is a good example. It is horrific
slow. Stepping through the code shows that there are complex multi-level
dynamic type conversion and dataaccess routines at almost every statement.
The typical C++ programmer does not need to care about because the
programming language takes care for the boring tasks. The typical C++
programmer actually *does* not care about performance because competing
programs are not faster; they are written in a modern programming language
too...
Recently I had to revive my stone old AMD-K6 PC with Windows 95. What marvel,
that relict with its age-old applications provides a better user experience,
is snappier, more convenient and more productive than my newest Linux machine
with the modern desktops and applications.

Martin
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A serious Memleak using delegates/implements (was: Delegate Interface class does not seem to be referenced counted)

Graeme Geldenhuys-6
On 2016-10-06 05:54, Martin Schreiber wrote:
> Recently I had to revive my stone old AMD-K6 PC with Windows 95. What marvel,
> that relict with its age-old applications provides a better user experience,
> is snappier, more convenient and more productive than my newest Linux machine
> with the modern desktops and applications.

We seem to have a lot in common. I still prefer Win2000 for any Windows
development (if I must use Windows). Memory efficient and very snappy
indeed! For Linux (actually FreeBSD) I long ago gave up on the extremely
bloated 'desktop environments' and have for years been using JWM (Joe's
Window Manager) - old school to the point, extremely fast and memory
efficient (8MB max) window manager. JWM stays out of my way, has hardly
any keyboard shortcuts to interfere with my daily programs, gives me a
task bar, virtual desktops and a popup menu. I don't need more than that.

Oh, and I run this on a Intel i7 3.5Ghz CPU with 32GB RAM. I prefer to
use my RAM for actual applications, VMs or the ZFS file system - not the
desktop environment. ;-)

Regards,
  Graeme

--
fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal
http://fpgui.sourceforge.net/

My public PGP key:  http://tinyurl.com/graeme-pgp
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A serious Memleak using delegates/implements (was: Delegate Interface class does not seem to be referenced counted)

Graeme Geldenhuys-6
In reply to this post by Tony Whyman
On 2016-10-05 23:16, Tony Whyman wrote:
> Used properly reference counted interfaces are very powerful and allow
> for some very elegant programming. Do you complain about AnsiStrings?

I have very powerful and elegant programming with CORBA interfaces too.
;-) Also as Martin mentioned, reference counting works wonders in simple
cases, but gets very nasty in medium to complex cases. I've seem some
COM Interface code where they had to resort to using raw Pointer types
etc to try and avoid reference counting and causing unexpected memory
leaks.  No such problems with CORBA Interfaces.

ps:
  You can obviously implement your own reference counted CORBA interface
  for the simple cases too. So you have the best of both worlds I guess,
  but when using CORBA Interfaces, I would avoid mixing reference
  counted and non-reference counted interfaces.

Regards,
  Graeme

--
fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal
http://fpgui.sourceforge.net/

My public PGP key:  http://tinyurl.com/graeme-pgp
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A serious Memleak using delegates/implements (was: Delegate Interface class does not seem to be referenced counted)

Graeme Geldenhuys-6
In reply to this post by Marcos Douglas B. Santos
On 2016-10-06 02:34, Marcos Douglas wrote:
> But, the result was the same, even using D7.
> So, is this by design? Sad...

Sad and nasty indeed. But it seems it is “by design” or done for “Delphi
compatibility”.

It would be interesting to know what Delphi developers think of this.
You should post the new code example and message to a Delphi newsgroup
or Google+ forum and see what they think of that. If it has been around
since the D7 days (and maybe even earlier), they might have an
explanation or work-around for you.

Regards,
  Graeme

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A serious Memleak using delegates/implements (was: Delegate Interface class does not seem to be referenced counted)

Graeme Geldenhuys-6
In reply to this post by Marcos Douglas B. Santos
On 2016-10-05 16:26, Marcos Douglas wrote:
> So, I coded a new example — more simpler, I think — to demonstrate the same
> problem and prove that there is some wrong that is causing a memleak.

And here is that example converted to use CORBA style interfaces and no
memory leaks.


Program output:

==========================================================
[tmp]$ ./test.exe

IntegerValue:
TIntegerValue.Create
Number is 5
TIntegerValue.Destroy

MyApp:
TIntegerValue.Create
TMyApp.Create
Number is 10
TIntegerValue.Destroy
TMyApp.Destroy

MyAppAsInterface:
TIntegerValue.Create
TMyApp.Create
Number is 20
TIntegerValue.Destroy
TMyApp.Destroy

Heap dump by heaptrc unit
29 memory blocks allocated : 2045/2080
29 memory blocks freed     : 2045/2080
0 unfreed memory blocks : 0
True heap size : 1409024 (32 used in System startup)
True free heap : 1408992

==========================================================


Regards,
  Graeme

--
fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal
http://fpgui.sourceforge.net/

My public PGP key:  http://tinyurl.com/graeme-pgp

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal

unit1.pas (2K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: A serious Memleak using delegates/implements (was: Delegate Interface class does not seem to be referenced counted)

Graeme Geldenhuys-6
In reply to this post by Marcos Douglas B. Santos
On 2016-10-06 02:49, Marcos Douglas wrote:
> I understand you, but reference counting help us to write a better
> code, more object-oriented.

That's got nothing to do with reference counting functionality. I use
object-oriented coding practices all the time, but I don't need
reference counting for that.


> I'm using decorator pattern. No problem with it, but delegates makes
> me write less code and the design is awesome.

So, nothing stops you from using interface delegates with CORBA style
interfaces. See the example code I just posted, where I converted the
original example to use CORBA style interfaces instead.

I'm a huge believer and user of design patterns, and most of them I've
implemented using Interfaces. Nothing there tells me I must use COM
style interfaces.


> For me, it's a bug. Sorry.

That I agree with. There seems to be a COM reference counted bug.


Regards,
  Graeme

--
fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal
http://fpgui.sourceforge.net/

My public PGP key:  http://tinyurl.com/graeme-pgp
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A serious Memleak using delegates/implements (was: Delegate Interface class does not seem to be referenced counted)

Tony Whyman
In reply to this post by Graeme Geldenhuys-6
On 06/10/16 11:08, Graeme Geldenhuys wrote:
> I've seem some
> COM Interface code where they had to resort to using raw Pointer types
> etc to try and avoid reference counting and causing unexpected memory
> leaks.
I have also seen plenty of examples of poor coding with classes, but the
fact that someone writes bad object oriented programs doesn't mean that
object oriented is a poor programming technique. Likewise, poor
programming using com interfaces doesn't invalidate the use of com
interfaces.

When you work with interfaces, there are two issues to consider:

1. How easy is the interface to use
2. How do you write the underlying classes.

To me, the first rules out delegated interfaces and COM. Even advanced
level programmers will get it wrong and you will never get an easy to
use interface with this combination. It looks like a design error that
came from Delphi and was copied by FPC. However, if you rule out this
combination, COM does make for what seems to be a very intuitive easy to
use interface, in the same way that AnsiStrings are easy to use.

On the other hand, implementing the classes that provide a com interface
does require some skill and is not for everyone.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A serious Memleak using delegates/implements (was: Delegate Interface class does not seem to be referenced counted)

Marcos Douglas B. Santos
In reply to this post by Graeme Geldenhuys-6
On Thu, Oct 6, 2016 at 7:11 AM, Graeme Geldenhuys
<[hidden email]> wrote:

> On 2016-10-06 02:34, Marcos Douglas wrote:
>> But, the result was the same, even using D7.
>> So, is this by design? Sad...
>
> Sad and nasty indeed. But it seems it is “by design” or done for “Delphi
> compatibility”.
>
> It would be interesting to know what Delphi developers think of this.
> You should post the new code example and message to a Delphi newsgroup
> or Google+ forum and see what they think of that. If it has been around
> since the D7 days (and maybe even earlier), they might have an
> explanation or work-around for you.

That's a good idea. I'll do it.

Marcos Douglas
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
123