Mutley2003
asked on
function returning TInterfacedObject
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(TinterfacedObj ect)
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.btnTestReferencecou ntingClick (Sender: TObject);
var k: integer; tom : TTom;
begin
tom := Ttom.create;
for k:=1 to 100 do begin
dsmemo1.out([tom.afred.AsS tring, 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
I don't know much about interfaces, but I thought the following might work
type
Tfred=class(TinterfacedObj
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.btnTestReferencecou
var k: integer; tom : TTom;
begin
tom := Ttom.create;
for k:=1 to 100 do begin
dsmemo1.out([tom.afred.AsS
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
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.
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.
In Delphi, it is far better to ensure that you free everything than to depend on the GC model.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
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
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
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.
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.
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
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.GetFre
finally
tom.Free;
end;
end;
{ TTom }
function TTom.GetFred: IFred;
begin
Result := TFred.Create;
end;
wbr, mo.