Solved

function returning TInterfacedObject

Posted on 2003-10-24
6
961 Views
Last Modified: 2011-09-20
It is convenient, in my code, for me to have a function returning an instance of an object without me having to worry about managing that instance .. in other words, I am looking for garbage collection.

I don't know much about interfaces, but I thought the following might work
type
Tfred=class(TinterfacedObject)
  private
  function getAsString: String;
public
  property AsString : String read getAsString;
end;


function Tfred.getAsString: String;
begin
result := inttostr(refCount);
end;

type
 Ttom = class
public
  function aFred: Tfred;
end; // Ttom

 function Ttom.aFred: Tfred;
 begin
  result :=Tfred.create;
  // never cleaned up
 end;


or even
function myFred:Tfred; begin result:=Tfred.create; end;


procedure TForm1.btnTestReferencecountingClick(Sender: TObject);
var k: integer; tom : TTom;

begin
tom := Ttom.create;
for k:=1 to 100 do begin
dsmemo1.out([tom.afred.AsString, myFred.AsString]);
end;
tom.free;
end;

Is this a correct usage of TinterfacedObject?

I don't think reference counting is going to come into it, but will all my instances of Tfred be released at the end of the calling procedure??

Also, I don't understand how the cleanup can happen correctly without Delphi maintaining some sort of internal list (in which case there would be a hidden overhead, compared to managing the lifetimes yourself). I understand the reference count is maintained with the object, but somehow - at run time - the app must tell the object that it is no longer in scope ..

enlightenment and code correction sought, please
0
Comment
Question by:Mutley2003
  • 4
6 Comments
 
LVL 9

Expert Comment

by:mocarts
ID: 9619156
Hi, Mutley :)
Your code will work, but you still need to free your objects, since reference counting is used only to interfaces.
TInterfaceObject is helper object which impelements AddRef, Release methods of IInterface. You should declare and implement your IFred interface to use reference counting..
here will be reworked code:

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
  end;

  IFred = interface
    function AsString: string;
  end;

  TFred = class(TInterfacedObject, IFred)
  public
    destructor Destroy; override;
    function AsString: string;
  end;

  TTom = class
    function GetFred: IFred;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TFred }

function TFred.AsString: string;
begin
  Result := inttostr(RefCount);
end;

destructor TFred.Destroy;
begin
  ShowMessage('Destroing');
  inherited;
end;

// simple function to get Fred
function GetFred: IFred;
begin
  Result := TFred.Create;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Tom: TTom;
  i: integer;
begin
  tom := TTOm.Create;
  try
    for i := 0 to 10 do
     // scope of IFred is limited only to this line
     //(actually there is two separate TFred interface instances used)
      Memo1.Lines.Add(Tom.GetFred.AsString + '; '+ GetFred.AsString);
  finally
    tom.Free;
  end;
end;

{ TTom }

function TTom.GetFred: IFred;
begin
  Result := TFred.Create;
end;

wbr, mo.
0
 
LVL 6

Expert Comment

by:swift99
ID: 9622500
Delphi's reference counting is, in my experience, not useful.  If you add an interface object to a list, for example, the reference count is not updated, so your objects may disappear "randomly", or fail yto be garbage collected and the reason not be apparent.
0
 
LVL 6

Expert Comment

by:swift99
ID: 9622509
Even in Java, you have to pay careful attention to the GC and the memory model, or it works against you rather than for you.  Java uses a access graph rather than a reference count, which is mroereliable, and even it has problems.

In Delphi, it is far better to ensure that you free everything than to depend on the GC model.
0
Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

 
LVL 6

Accepted Solution

by:
swift99 earned 500 total points
ID: 9623912
Delphi does not manage a list.  Every call to the object through the TInterfacedObject code checks reference count.  If reference count is zero then it frees the object.

This leads to interesting effects if you create an object, add it to a list, and then attempt to perform some operations against it.  The first operation succeeds, but it also frees the object.  The second operation fails randomly because the object has been freed, and its memory (which you are still pointing at) is in an indeterminate state.

The overhead of this is huge.  In the same code, going through both the "interface" model and the pure inheritance model, the interface model was able to perform 5,000 operations per second.  The identical code, refactored to use the pure inheritance model, was able to perform 12,000,000 operations per second.

All tests were performed under Windows 98 on the same 800 MHz machine.  At the higher speed, a complete regression test takes roughly 11 hours, so you can see why I threw out the interface model once I did force it to work.
0
 

Author Comment

by:Mutley2003
ID: 9661515
swift99

ok, I am convinced. With only a little more work I can use the traditional approach, and with results like the ones you have obtained, I see no reason to venture into the uncharted waters of interfaces and garbage collection

thanks
0
 
LVL 6

Expert Comment

by:swift99
ID: 9662885
The implementation of the "interface" concept in Delphi was tied in to COM.  This was a deliberate decision because of the way that Windows architecture was going.  It is not fair to write off the interfaces approach entirely

Delphi Interfaces are still useful in two places:
1. any interaction through the COM or ActiveX API - say a DLL that implements a COM object for use by an outsode program
2. operations where performance is not an issue, and you can control the refernces yourself - for example the DUnit testing framework

In Java, the designers did not labour under the need to conform to a M$oft architecture direction of the week, so interfaces are implemented as a parallel VMT (array of pointers) and are very light weight.

Interfaces and garbage collection should be considered as two independent questions, even though they have been rolled together in the Delphi model.  I think that the Delphi architects recognize this flaw, but too much code has been written for this blurred paradigm for them to arbitrarily change it and break their customers' code base.
0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now