Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Interfaces

1 view
Skip to first unread message

Frank Shearar

unread,
Nov 28, 2001, 5:26:59 AM11/28/01
to
Hi all.

The light finally dawned for me regarding interfaces, and what is going
wrong with the way I use them.

Consider something like

TFoo = class(TObject, IFoo)
private
FFoo: IFoo;
protected
// do the _AddRef, _Release implementations here that don't do reference
counting
public
function GetArb: IFoo;
procedure SetArb(const Value: IFoo);
end;

function TFoo.GetArb: IFoo;
begin
Result := FFoo;
end;

procedure TFoo.SetArb(const Value: IFoo);
begin
FFoo := Value;
end;

Consider now the code:

var
Foo, F : TFoo;
begin
Foo := TFoo.Create;
try
F := TFoo.Create;
Foo.SetArb(F);
finally
F.Free;
end;
Foo.SetArb(nil);
finally
Foo.Free;
end;
end;

If this was done purely with objects, the code would be fine - you're
killing the association between Foo and F. However, with interfaces the call
to Foo.SetArb(nil) will access violate since Delphi's "compiler magic" will
call _Release on the object pointed to by FFoo, which has been freed.

Hm. Is my thinking correct in this regard? Or is the light merely a false
dawn?

If I'm right, then I've found the core of what I resent about interfaces. I
don't _want_ _AddRef and _Release called. I'd love to be able to turn off
the "compiler magic" and use interfaces just like objects. I mean, a
compiler directive along the lines of {$ANNOYING_INTERFACE_MAGIC OFF} would
seriously make my day!

frank


Joanna Carter

unread,
Nov 28, 2001, 6:51:56 AM11/28/01
to
"Frank Shearar" <frank@spambounce.x> a écrit dans le message news:
3c04bbf8_1@dnews...

> If this was done purely with objects, the code would be fine - you're
> killing the association between Foo and F. However, with interfaces the
call
> to Foo.SetArb(nil) will access violate since Delphi's "compiler magic"
will
> call _Release on the object pointed to by FFoo, which has been freed.
>
> Hm. Is my thinking correct in this regard? Or is the light merely a false
> dawn?
>
> If I'm right, then I've found the core of what I resent about interfaces.
I
> don't _want_ _AddRef and _Release called. I'd love to be able to turn off
> the "compiler magic" and use interfaces just like objects. I mean, a
> compiler directive along the lines of {$ANNOYING_INTERFACE_MAGIC OFF}
would
> seriously make my day!

In the following example, a tree node has a parent that is a treenode, this
problem of reference counting means the parent has a reference to the child
and the child has a reference to the parent.

ITreeNode = interface
['{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}']
function GetChildren: INodeList;
function GetParent: ITreeNode;
function AddChild: ITreeNode;
property Children: INodeList
read GetChildren;
property Parent: ITreeNode
read GetParent;
end;

TTreeNode = class(TInterfacedObject, ITreeNode)
private
fChildren: INodeList;
fParent: Pointer;
function GetChildren: INodeList;
function GetParent: ITreeNode;
function AddChild: ITreeNode;
public
constructor Create(const Parent: ITreeNode);
destructor Destroy; override;
end;

To implement this relationship fParent is declared as a Pointer then in the
constructor you use the following :

constructor TTreeNode.Create(const Parent: ITreeNode);
begin
inherited Create;
fParent := Pointer(Parent);
end;

The cast to a Pointer avoids incrementing the Reference Count. Similarly to
get hold of the Parent you use a GetParent method implemented like this :

function TTreeNode.GetParent: ITreeNode;
begin
Result := ITreeNode(fParent);
end;

This gives you back the variable as the correct type without incrementing
the reference count.

The compiler magic will ensure that free is never called on the inner
object, which is only a copy reference, therefore avoiding access violations
when the destructor of the outer object tries to set an interface reference
to nil.

Joanna

Frank Shearar

unread,
Nov 28, 2001, 8:02:46 AM11/28/01
to

"Joanna Carter" <joa...@btinternet.com> wrote in message
news:3c04cfcb$1_1@dnews...

> "Frank Shearar" <frank@spambounce.x> a écrit dans le message news:
> 3c04bbf8_1@dnews...
<snip my semirant and Joanna's example of "weak reference"

>
> This gives you back the variable as the correct type without incrementing
> the reference count.
>
> The compiler magic will ensure that free is never called on the inner
> object, which is only a copy reference, therefore avoiding access
violations
> when the destructor of the outer object tries to set an interface
reference
> to nil.

Yes, Bjørge Sæther mentioned this method of doing things in the thread
titled "Interface ref counting". What I've found, on further delving, is the
following:

We have

IFoo = interface(IUnknown)
['{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}']
function GetBar: IFoo;
procedure SetBar(const Value: IFoo);
end;

TFoo = class(TObject, IFoo)
private

FBar: Pointer;
protected
{ implement non-reference-counting stuff: _AddRef &
_Release return -1; QueryInterface is cut-and-pasted
from TInterfacedObject}
public
destructor Destroy; override;
function GetBar: IFoo;
procedure SetBar(const Value: IFoo);
end;

{ using the "weak reference" method for accessors }
function TFoo.GetBar: IFoo;
begin
Result := IFoo(FBar);
end;

procedure TFoo.SetBar(const Value: IFoo);
begin
FBar := Pointer(Value);
end;

Now we have test code ExhibitA:

procedure Check_TFoo.VerifyGetSetStock;
var
F, Foo: TFoo;
FI: IFoo;


begin
Foo := TFoo.Create;
try
F := TFoo.Create;

try
FI := F;
Foo.SetBar(F);
Check(FI = Foo.GetBar, '');
finally
FI := nil;
F.Free;
end;
finally
Foo.Free;
end;
end;

This access violates in Foo.Free.

and ExhibitB:

procedure Check_TFoo.VerifyGetSetStock;
var
F, Foo : TFoo;
FI, FI2: IFoo;


begin
Foo := TFoo.Create;
try
F := TFoo.Create;

try
FI := F;
Foo.SetBar(F);
FI2 := Foo.GetBar;
Check(FI = FI2, 'Bar');
finally
FI := nil;
FI2 := nil;
F.Free;
end;
finally
Foo.Free;
end;
end;

which works perfectly.

In ExhibitA, we have two calls to _AddRef on "FI := F" and "Check(FI =
Foo.GetBar, '');", and one call to _Release, on "FI := nil".

In ExhibitB we have two calls to both _AddRef and _Release.

Why ExhibitA should access violate, though, is quite beyond me. When
stepping through the execution, the exception appears to be raised just
after the call to Foo.Free, which indicates that compiler magic is raising
the exception?

frank


Alex Yackimoff

unread,
Nov 28, 2001, 9:11:41 AM11/28/01
to

"Frank Shearar" <frank@spambounce.x> wrote in message
news:3c04bbf8_1@dnews...

> If this was done purely with objects, the code would be fine - you're
> killing the association between Foo and F. However, with interfaces the
call
> to Foo.SetArb(nil) will access violate since Delphi's "compiler magic"
will
> call _Release on the object pointed to by FFoo, which has been freed.

No, AFAIK, it won't call _Release unless FFoo is not nil. You've just
created this object, FFoo is nil. The problem may be in "const" in your
function declaration. I've recently read list of known issues for Delphi 5
and it says that when you use "const" in parameter declaration, compiler
doesn't do anything (i.e. doesn't call _AddRef or _Release).

--
Alex Yackimoff | http://yackimoff.cjb.net


Joanna Carter

unread,
Nov 28, 2001, 11:57:38 AM11/28/01
to
"Frank Shearar" <frank@spambounce.x> a écrit dans le message news:
3c04e085_1@dnews...

> TFoo = class(TObject, IFoo)
> private
> FBar: Pointer;
> protected
> { implement non-reference-counting stuff: _AddRef &
> _Release return -1; QueryInterface is cut-and-pasted
> from TInterfacedObject}
> public
> destructor Destroy; override;
> function GetBar: IFoo;
> procedure SetBar(const Value: IFoo);
> end;

Why not just inherit from TIn terfacedObject? This looks after 8AddRef and
8RElease, etc automatically.

> Now we have test code ExhibitA:
>
> procedure Check_TFoo.VerifyGetSetStock;
> var
> F, Foo: TFoo;
> FI: IFoo;
> begin
> Foo := TFoo.Create;
> try
> F := TFoo.Create;
> try
> FI := F;
> Foo.SetBar(F);
> Check(FI = Foo.GetBar, '');
> finally
> FI := nil;
> F.Free;
> end;
> finally
> Foo.Free;
> end;
> end;

you are mixing Interface and Object references here and that can end in
tears.

You should at least call Foo.SetBar(F as IFoo) and all instances should be
IFoo. Never use object refs in this way.

All methods that take interface parameters should declare them as const,
this avoids needless refcounting going in and out of the function.


> Why ExhibitA should access violate, though, is quite beyond me. When
> stepping through the execution, the exception appears to be raised just
> after the call to Foo.Free, which indicates that compiler magic is raising
> the exception?

I have learnt to use the interfaces only rule and weak pointers and it just
simply works every time; don't get a headache trying to work it out! <g>

Joanna


Alex Yackimoff

unread,
Nov 28, 2001, 12:22:28 PM11/28/01
to

"Joanna Carter" <joa...@btinternet.com> wrote in message
news:3c05177a_1@dnews...

> You should at least call Foo.SetBar(F as IFoo) and all instances should be
> IFoo. Never use object refs in this way.

Do you think there is a difference? If I remember correctly, _AddRef is
still called when using "Foo.SetBar(F)" since parameter type is interface, I
think on compile stage both this constructs are treated as equal.

Frank Shearar

unread,
Nov 28, 2001, 3:36:46 PM11/28/01
to

"Joanna Carter" <joa...@btinternet.com> wrote in message
news:3c05177a_1@dnews...

> "Frank Shearar" <frank@spambounce.x> a écrit dans le message news:
> 3c04e085_1@dnews...
>
> > TFoo = class(TObject, IFoo)
<snip>

> Why not just inherit from TIn terfacedObject? This looks after 8AddRef and
> 8RElease, etc automatically.
Yes, I could. Except I detest reference counting.

> you are mixing Interface and Object references here and that can end in
> tears.

I know one cannot mix reference counted interfaces and objects without
tears, because of lifetime management issues. What is grating me is that
Delphi doesn't seem to be able to do what Java can, in the way of
interfaces. I keep feeling that if it wasn't for the compiler magic
calling _AddRef and _Release all the time my problems would all vanish.

> You should at least call Foo.SetBar(F as IFoo) and all instances should be
> IFoo. Never use object refs in this way.

Thing is, Foo.SetBar(F) works in ExhibitB. What I don't get is why I should
have calls to _AddRef and _Release rammed down my throat by the compiler,
really. And why ExhibitB should work while ExhibitA doesn't.

> All methods that take interface parameters should declare them as const,
> this avoids needless refcounting going in and out of the function.

Noted :)

> > Why ExhibitA should access violate, though, is quite beyond me. When
> > stepping through the execution, the exception appears to be raised just
> > after the call to Foo.Free, which indicates that compiler magic is
raising
> > the exception?
>
> I have learnt to use the interfaces only rule and weak pointers and it
just
> simply works every time; don't get a headache trying to work it out! <g>

I've read of people not using reference counted interfaces and having
great success in their projects - so far, I've only seen that either one
has interfaces, reference counted, or one doesn't. Obviously I'm missing
something here, and I'd really like someone to point out to me what it is
:).

Thanks for your input, Joanna!

frank


Rudy Velthuis (TeamB)

unread,
Nov 28, 2001, 3:45:12 PM11/28/01
to
In article <3c054ae2_2@dnews>, Frank Shearar says...

> Yes, I could. Except I detest reference counting.

Why (this is a serious question)?
--
Rudy Velthuis (TeamB)

Jimmy [Used-Disks]

unread,
Nov 28, 2001, 4:27:47 PM11/28/01
to
"Frank Shearar" <frank@spambounce.x> wrote in news:3c04bbf8_1@dnews:

> If this was done purely with objects, the code would be fine - you're
> killing the association between Foo and F. However, with interfaces the
> call to Foo.SetArb(nil) will access violate since Delphi's "compiler
> magic" will call _Release on the object pointed to by FFoo, which has
> been freed.

If you're not implementing reference counting, then the call's to _AddRef and
_Release don't (really "shouldn't") have any affect.

--
- Jimmy
http://www.used-disks.com/programming
http://www.insider-info.com/Music/Boetz/
:

Frank Shearar

unread,
Nov 28, 2001, 5:00:27 PM11/28/01
to
"Jimmy [Used-Disks]" <ji...@NILSMAPused-disks.com> wrote in message
news:Xns9167A74519E88ji...@207.105.83.65...

> "Frank Shearar" <frank@spambounce.x> wrote in news:3c04bbf8_1@dnews:
>
> > If this was done purely with objects, the code would be fine - you're
> > killing the association between Foo and F. However, with interfaces the
> > call to Foo.SetArb(nil) will access violate since Delphi's "compiler
> > magic" will call _Release on the object pointed to by FFoo, which has
> > been freed.
>
> If you're not implementing reference counting, then the call's to _AddRef
and
> _Release don't (really "shouldn't") have any affect.
Agreed. But the compiler magic still does its thing calling _AddRef and
_Release.

In the example I gave, the object to which FFoo, in the setter, pointed to
had been freed. Thus, when the call to "FFoo := nil" happened, _Release was
called on the freed object, and an access violation occured.

I worked around that by using the "weak reference" trick that's been
mentioned
recently.

Not that my interface troubles are over, as you've no doubt seen by my other
post in this thread.

frank


Iman L Crawford

unread,
Nov 28, 2001, 5:12:13 PM11/28/01
to
"Frank Shearar" <frank@spambounce.x> wrote in news:3c054ae2_2@dnews:

> "Joanna Carter" <joa...@btinternet.com> wrote in message
> news:3c05177a_1@dnews...
>> "Frank Shearar" <frank@spambounce.x> a écrit dans le message news:
>> 3c04e085_1@dnews...
>>
>> > TFoo = class(TObject, IFoo)
><snip>
>> Why not just inherit from TIn terfacedObject? This looks after 8AddRef
>> and 8RElease, etc automatically.
> Yes, I could. Except I detest reference counting.

Well implement IInterface for in all you objects you use interfaces on, and
don't do any reference counting.

--
Iman
` A word of warning about Emma, though - she's not really a "frisbee"
girl, as it turns out. No lie. We played for a while on Saturday at
Gasworks Park, and she either just really sucks or she's throwing to
people we can't see' - www.penny-arcade.com

Frank Shearar

unread,
Nov 28, 2001, 5:10:54 PM11/28/01
to
"Rudy Velthuis (TeamB)" <rvel...@gmx.de> wrote in message
news:MPG.166f6b3f8...@newsgroups.borland.com...

> In article <3c054ae2_2@dnews>, Frank Shearar says...
>
> > Yes, I could. Except I detest reference counting.
>
> Why (this is a serious question)?

It's a question of control, really. I want to be the one telling
the objects when to free.

I have been bitten once or twice by reference counting, which
admittedly could be me being silly, although I did expend a
considerable effort checking my code for things like mixing
reference counted interfaces and objects.

I'm not sure if this is a relevant objection, but what I'm after
is to have different levels of access to objects - for instance,
a Bill object might have a TransactionDate property that needs
to be read only. However, the classes that create this Bill and
populate it with info from the persistence layer must obviously
be able to set it, and I don't want to have to pass a potentially
large number of parameters in to a constructor. Thus I'd be mixing
object and interface references, and since objects and reference
counted interfaces use differing lifetime managements I'd be
looking at some nasty bugs very quickly.

One alternative which had sprung to mind is to have, say, the Bill
object (TBill) implement two interfaces - IBill and IBillSuper or
something, where IBillSuper would allow write access to the properties
that were read only in IBill.

frank


Greg Chapman

unread,
Nov 28, 2001, 5:33:34 PM11/28/01
to
On Wed, 28 Nov 2001 15:02:46 +0200, "Frank Shearar" <frank@spambounce.x> wrote:

>
>
>Now we have test code ExhibitA:
>
>procedure Check_TFoo.VerifyGetSetStock;
>var
> F, Foo: TFoo;
> FI: IFoo;
>begin
> Foo := TFoo.Create;
> try
> F := TFoo.Create;
> try
> FI := F;
> Foo.SetBar(F);
> Check(FI = Foo.GetBar, '');

The above line translates to:

var Temp: IFoo;
Temp:= Foo.GetBar;
Check(FI=Temp, '');

(In essence, the compiler does exactly what you did in Exhibit B, except the
Temp (FI2) reference is hidden.) You now have a Temp IFoo which the compiler
will attempt to clean up at the end of the procedure: since you will have freed
the object used to implement that IFoo (i.e., F), you get the access violation.

> finally
> FI := nil;
> F.Free;
> end;
> finally
> Foo.Free;
> end;
>end;
>

---
Greg Chapman

Bjørge Sæther

unread,
Nov 28, 2001, 6:57:42 PM11/28/01
to
"Frank Shearar" <frank@spambounce.x> skrev i melding news:3c0560f5_1@dnews...

> "Rudy Velthuis (TeamB)" <rvel...@gmx.de> wrote in message
> news:MPG.166f6b3f8...@newsgroups.borland.com...
> > In article <3c054ae2_2@dnews>, Frank Shearar says...
> >
> > > Yes, I could. Except I detest reference counting.
> >
> > Why (this is a serious question)?
>
> It's a question of control, really. I want to be the one telling
> the objects when to free.
>
> I have been bitten once or twice by reference counting, which
> admittedly could be me being silly, although I did expend a
> considerable effort checking my code for things like mixing
> reference counted interfaces and objects.
>
> I'm not sure if this is a relevant objection, but what I'm after
> is to have different levels of access to objects - for instance,
> a Bill object might have a TransactionDate property that needs
> to be read only. However, the classes that create this Bill and
> populate it with info from the persistence layer must obviously
> be able to set it, and I don't want to have to pass a potentially
> large number of parameters in to a constructor. Thus I'd be mixing
> object and interface references, and since objects and reference
> counted interfaces use differing lifetime managements I'd be
> looking at some nasty bugs very quickly.

It isn't as simple as saying "don't mix interface and object access, and the
trouble is gone", because there are cases where one *needs* accessing both
the interface and the object. Two situations I can think of:
a) When mimicking MI, where an interface is used for establishing a second
"dimension".
b) When interfaces are generic (like patterns), but you don't want to limit
your programming to using only the interface. The Interface may be used by a
control or a Persistence framework, but the rest of your application would
use the object.

To me the question rather seems like: "Do I want RefCounting ?" If not, then
implement methods returning -1, and only remember that you allways need to
nil' interface references before freeing the object.

It just fell into my mind: I created a "both ways-thingy": the Trash;
method...

IVUnknown = interface(IUnknown)
['{054E1DE1-F83E-11D3-A654-0000C0A8D864}']
function _Self: TObject;
procedure Trash; // When Trash; is called, automatic destroy; is invoked
when refcount reaches 0
end;

TVStringParams = class(TStringList, IVUnknown)
private
function_AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
public
function _Self: TObject;
procedure Trash;
end;

function TVStringParams._AddRef: Integer;
begin
if FRefCount < 0 then
dec(FRefCount)
else
inc(FRefCount);
result:=Abs(FRefCount);
end;

function TVStringParams._Release: Integer;
begin
if FRefCount < 0 then begin
inc(FRefCount);
if FRefCount = 0 then
Free
else
result:=-FRefCount;
end
else begin
dec(FRefCount);
Result:=FRefCount;
end;
end;

function TVStringParams.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
if GetInterface(IID, Obj) then
result:=0
else
result:=E_NOINTERFACE;
end;

function TVStringParams._Self: TObject;
begin
result:=Self;
end;

procedure TVStringParams.Trash;
begin
if FRefCount > 0 then
FRefCount:=-FRefCount;
end;

...handy ?

--
Bjørge Sæther
Konsulent & Utvikler
bjo...@itte.no
Kontor: Strøket 41, 1383 ASKER
Post: Drengsrudveien 44, 1385 ASKER
Telefon +47 66 75 86 00
Fax +47 66 75 86 01
Mobil +47 90 82 22 39
Privat +47 66 90 38 61


Frank Shearar

unread,
Nov 29, 2001, 2:53:09 AM11/29/01
to

"Bjørge Sæther" <bjorge@hahaha_itte.no> wrote in message
news:3c0579a3_1@dnews...

These two points are precisely why I'm trying to get interfaces to work.
I've
started looking for code now, to see how other people are using
non-reference
counted interfaces. Any pointers?

> To me the question rather seems like: "Do I want RefCounting ?" If not,
then
> implement methods returning -1, and only remember that you allways need to
> nil' interface references before freeing the object.

This is what I'm doing. There just seems to be other stuff that I'm missing
though, like perhaps the correct way to pass interfaces around or something,
because I keep on getting weird access violations where I shouldn't be, and
every time I do it's invariably just after the Destroy has just finished
executing or just after a block finishes executing. And yes, I am setting
my interface variables to nil :).

For example, the following, according to my instincts, should work with
no funny side effects:

IFoo = interface(ISomeArbInterface);
TFoo = class(TNotReferenceCounted, IFoo);

procedure Bar.DoSomething(const F : TFoo);

and then somewhere calling
Foo := TFoo.Create;
Bar := TBar.Create;
Bar.DoSomething(F);

(I am, of course, ignoring irrelevancies like try..finally etc)

> It just fell into my mind: I created a "both ways-thingy": the Trash;
> method...
>
> IVUnknown = interface(IUnknown)
> ['{054E1DE1-F83E-11D3-A654-0000C0A8D864}']
> function _Self: TObject;
> procedure Trash; // When Trash; is called, automatic destroy; is
invoked
> when refcount reaches 0
> end;

<snip>
I see... the object is not reference counted until you call Trash,
basically?

frank


Rudy Velthuis (TeamB)

unread,
Nov 29, 2001, 8:02:43 AM11/29/01
to
In article <3c0579a3_1@dnews>, Bjørge Sæther says...

> It isn't as simple as saying "don't mix interface and object access, and the
> trouble is gone", because there are cases where one *needs* accessing both
> the interface and the object. Two situations I can think of:
> a) When mimicking MI, where an interface is used for establishing a second
> "dimension".

I am not quite sure what you mean here. Why would you need to use the
object interface?

> b) When interfaces are generic (like patterns), but you don't want to limit
> your programming to using only the interface. The Interface may be used by a
> control or a Persistence framework, but the rest of your application would
> use the object.

In that case, expose other interfaces as well, and query them.
--
Rudy Velthuis (TeamB)

Rudy Velthuis (TeamB)

unread,
Nov 29, 2001, 8:08:54 AM11/29/01
to
In article <3c0560f5_1@dnews>, Frank Shearar says...

> I'm not sure if this is a relevant objection, but what I'm after
> is to have different levels of access to objects - for instance,
> a Bill object might have a TransactionDate property that needs
> to be read only. However, the classes that create this Bill and
> populate it with info from the persistence layer must obviously
> be able to set it, and I don't want to have to pass a potentially
> large number of parameters in to a constructor. Thus I'd be mixing
> object and interface references, and since objects and reference
> counted interfaces use differing lifetime managements I'd be
> looking at some nasty bugs very quickly.

Your creating class could create the TBill as an object, set all
necessary properties and then assign it to an interface reference. Only
from that point on, your object shouldn't be accessed as an object
anymore. Before that, no reference counting is done. The interface
should of course only expose the GetTransactionDate function.

var
MyTBill: TBill;
MyIBill: IBill;

MyTBill := TBill.Create;
try
// set properties

MyIBill := MyBill;
finally
...
end;



> One alternative which had sprung to mind is to have, say, the Bill
> object (TBill) implement two interfaces - IBill and IBillSuper or
> something, where IBillSuper would allow write access to the properties
> that were read only in IBill.

Also a possibility.
--
Rudy Velthuis (TeamB)

Rudy Velthuis (TeamB)

unread,
Nov 29, 2001, 8:11:52 AM11/29/01
to
In article <3c055e7f_2@dnews>, Frank Shearar says...

> > If you're not implementing reference counting, then the call's to _AddRef
> > and _Release don't (really "shouldn't") have any affect.

> Agreed. But the compiler magic still does its thing calling _AddRef and
> _Release.

And in what way is that bad? Are you worried about performance?
--
Rudy Velthuis (TeamB)

Bjørge Sæther

unread,
Nov 29, 2001, 8:21:28 AM11/29/01
to
"Frank Shearar" <frank@spambounce.x> skrev i melding news:3c05e969_1@dnews...

>
> "Bjørge Sæther" <bjorge@hahaha_itte.no> wrote in message
> > It isn't as simple as saying "don't mix interface and object access, and
> the
> > trouble is gone", because there are cases where one *needs* accessing
both
> > the interface and the object. Two situations I can think of:
> > a) When mimicking MI, where an interface is used for establishing a
second
> > "dimension".
> > b) When interfaces are generic (like patterns), but you don't want to
> limit
> > your programming to using only the interface. The Interface may be used
by
> a
> > control or a Persistence framework, but the rest of your application
would
> > use the object.
>
> These two points are precisely why I'm trying to get interfaces to work.
> I've
> started looking for code now, to see how other people are using
> non-reference
> counted interfaces. Any pointers?

Sorry, I know the low-lwvwl stuff but little about practical programming
techniques here. I'm using interfaces daily, but in the @Intf - version
(Pointers to Interfaces), so I don't have problems either with RefCounting or
interface copying when going in and out of scope. Maybe I'm a coward....;-)

> > To me the question rather seems like: "Do I want RefCounting ?" If not,
> then
> > implement methods returning -1, and only remember that you allways need
to
> > nil' interface references before freeing the object.
>
> This is what I'm doing. There just seems to be other stuff that I'm missing
> though, like perhaps the correct way to pass interfaces around or
something,
> because I keep on getting weird access violations where I shouldn't be, and
> every time I do it's invariably just after the Destroy has just finished
> executing or just after a block finishes executing. And yes, I am setting
> my interface variables to nil :).

You need to do the same thing *internally* in an object, too. You knew that ?

> > It just fell into my mind: I created a "both ways-thingy": the Trash;
> > method...
> >
> > IVUnknown = interface(IUnknown)
> > ['{054E1DE1-F83E-11D3-A654-0000C0A8D864}']
> > function _Self: TObject;
> > procedure Trash; // When Trash; is called, automatic destroy; is
> invoked
> > when refcount reaches 0
> > end;
> <snip>
> I see... the object is not reference counted until you call Trash,
> basically?

Yes. After posting this, I realized it should possibly be done the other way
around: RefCounted until you call Keep; method, which works exactly opposite
from Trash;...

Bjørge Sæther

unread,
Nov 29, 2001, 8:36:33 AM11/29/01
to
"Rudy Velthuis (TeamB)" <rvel...@gmx.de> skrev i melding
news:MPG.167052851...@newsgroups.borland.com...

Performance *is* a problem with interfaces. Try to paint a grid with 15
columns and 30 lines and let all cell values & properties be accessed via
Interfaces, and you'll see...

Bjørge Sæther

unread,
Nov 29, 2001, 8:34:49 AM11/29/01
to
"Rudy Velthuis (TeamB)" <rvel...@gmx.de> skrev i melding
news:MPG.1670505c8...@newsgroups.borland.com...

> In article <3c0579a3_1@dnews>, Bjørge Sæther says...
>
> > It isn't as simple as saying "don't mix interface and object access, and
the
> > trouble is gone", because there are cases where one *needs* accessing
both
> > the interface and the object. Two situations I can think of:
> > a) When mimicking MI, where an interface is used for establishing a
second
> > "dimension".
>
> I am not quite sure what you mean here. Why would you need to use the
> object interface?

The reason you create *one* interface is that all you need is to get a
"polymorphic behaviour" for a "class"(=interface) other than the ancestor
class. You could of course turn *both* desired "classes" into interfaces, but
why, if all you want is to circumvent lack of MI in Delphi ?

> > b) When interfaces are generic (like patterns), but you don't want to
limit
> > your programming to using only the interface. The Interface may be used
by a
> > control or a Persistence framework, but the rest of your application
would
> > use the object.
>
> In that case, expose other interfaces as well, and query them.

I feel that the best argumnent for using interfaces is that they allow for a
quicker, more "to-the-point" - programming as you don't need to create
complex, well-designed base classes. If interfaces are as detailed and
specialized as classes normally are, you loose all of this, IMHO. You may
write classes loded with snacky functionality, even if interfaces are simple.
parts of your application wouldn't know the difference, but some parts
certainly would.

I believe the best way to use interfaces is by thinking in two layers:
The application specific classes = the practical implementation much like
it's allways be done
The Interfaces & the reused classes = the "API" for generalized functionality
like Persistence, Controls, Language support, Modules, Actions, etc...

Frank Shearar

unread,
Nov 29, 2001, 9:11:18 AM11/29/01
to
"Rudy Velthuis (TeamB)" <rvel...@gmx.de> wrote in message
news:MPG.167052851...@newsgroups.borland.com...

No, I want to be able to say to the compiler "Listen here. I don't _want_
you
to call _AddRef/_Release." I don't like the compiler doing this magic stuff
for me, or at least I'd like to be able to turn it off.

All I want to worry about with interfaces is that it means that the instance
can respond to certain messages/execute certain methods. I don't want to
have
to worry about whether some variable is an interface variable or an object
variable because that's not how I'm thinking about the objects. It's that
slight mismatch between Delphi & my thinking that's causing friction, I
suspect.

As an example, you can do something like

var
O, Arb: TObject;
begin
O := TObject.Create;
try
Arb := O;
finally
O.Free;
end;
end;

without even thinking about it. But with interfaces suddenly you have to
ensure that your interfaces are nil by the end of the current scope, or
you have to worry about how/when _AddRef/_Release are going to be called,
etc.

frank


Joanna Carter

unread,
Nov 29, 2001, 9:55:51 AM11/29/01
to
"Frank Shearar" <frank@spambounce.x> a écrit dans le message news:
3c064249_1@dnews...

> As an example, you can do something like
>
> var
> O, Arb: TObject;
> begin
> O := TObject.Create;
> try
> Arb := O;
> finally
> O.Free;
> end;
> end;
>
> without even thinking about it. But with interfaces suddenly you have to
> ensure that your interfaces are nil by the end of the current scope, or
> you have to worry about how/when _AddRef/_Release are going to be called,
> etc.

How about :

var
O, Arb: IInterface;
begin
O := TInterfacedObject.Create;
Arb := O;
end;

Both references are released at the end of the proc. and the last one to be
released calls Destroy internally.

Now I think that requires less thinking!!

Joanna


Frank Shearar

unread,
Nov 29, 2001, 10:20:07 AM11/29/01
to

"Joanna Carter" <joa...@btinternet.com> wrote in message
news:3c064c69$1_1@dnews...
Yes, you can do that - but I don't like reference counting :). At least, not
in Delphi. That said, I'm prepared to admit that I'm being a bit
unreasonable
with regards to Delphi's implementation of the interface concept. I just
don't
like having to work around things - to write code such that I can avoid the
compiler inserting code I didn't ask for.

frank


Joanna Carter

unread,
Nov 29, 2001, 10:58:13 AM11/29/01
to
"Frank Shearar" <frank@spambounce.x> a écrit dans le message news:
3c06522e_2@dnews...

> Yes, you can do that - but I don't like reference counting :). At least,
not
> in Delphi. That said, I'm prepared to admit that I'm being a bit
> unreasonable
> with regards to Delphi's implementation of the interface concept. I just
> don't
> like having to work around things - to write code such that I can avoid
the
> compiler inserting code I didn't ask for.

Maybe it's because I use Interfaces all the time, but I can't see what you
mean about having to work around things.

I don't 'work around' anything; I just use interfaces in the way they were
designed and find that it makes design, coding and re-use much easier.

The top and bottom of it is that interface pointers are automatically
garbage collected and will stay in scope only as long as you have one
reference to them. You don't have to free them explicitly, or even set them
to nil, all that is automatic.

Could I just ask whether you are writing 'proper' OO code (no methods or
fields outside of classes). If not then this can seem to complicate matters.

Joanna


Franz-Leo Chomse

unread,
Nov 29, 2001, 11:55:35 AM11/29/01
to

>Yes, you can do that - but I don't like reference counting :). At least, not
>in Delphi. That said, I'm prepared to admit that I'm being a bit
>unreasonable with regards to Delphi's implementation of the interface concept. I just
>don't like having to work around things - to write code such that I can avoid the
>compiler inserting code I didn't ask for.

At least one who will not switch to Java or .Net. These environments
are fully managed and only know reference counted objects. There isn't
a method for destroying an object.

Regards from Germany

Franz-Leo

Marc Rohloff

unread,
Nov 29, 2001, 12:03:42 PM11/29/01
to
I think that the problem with interfaces in Delphi is that interfaces
use reference counting and objects don't.

Now if they both used reference counting like Java then most problems
would be solved (Ignoring the self reference problems)
Alternatively if nobody used Reference Counting I also think we would
be better off.

I personally tend to disable it if I need to use the objects.

Marc Rohloff

Rudy Velthuis (TeamB)

unread,
Nov 29, 2001, 12:56:42 PM11/29/01
to
In article <3c06398e_2@dnews>, Bjørge Sæther says...

> I feel that the best argumnent for using interfaces is that they allow for a
> quicker, more "to-the-point" - programming as you don't need to create
> complex, well-designed base classes. If interfaces are as detailed and
> specialized as classes normally are, you loose all of this, IMHO.

I think the argument for interfaces is that they represent the type
mechanism, and that classes represent the implementation mechanism.

So the interfaces define the what, the classes the how of a hierarchy,
or even of an entire program. I agree that this is best done by making
interfaces rather simple, and each interface specialises in one aspect.

But this is not always possible. Sometimes it makes sense to make an
interface a little more complex, and, depending on the demands (speed
vs. size, random vs. sequential access, etc.), you choose the best class
to implement it.

So the other nice thing about interfaces is, that it releases you of
implementation inheritance. A class in any hierarchy can implement an
interface.
--
Rudy Velthuis (TeamB)

Rudy Velthuis (TeamB)

unread,
Nov 29, 2001, 1:07:08 PM11/29/01
to
In article <3c06398f_2@dnews>, Bjørge Sæther says...

> Performance *is* a problem with interfaces. Try to paint a grid with 15
> columns and 30 lines and let all cell values & properties be accessed via
> Interfaces, and you'll see...

Of course that depends on the interface, and how many values it delivers
at once. <g>
--
Rudy Velthuis (TeamB)

Rudy Velthuis (TeamB)

unread,
Nov 29, 2001, 1:17:55 PM11/29/01
to
In article <u0qc0ugps9imag9i6...@4ax.com>, Franz-Leo
Chomse says...

> At least one who will not switch to Java or .Net. These environments
> are fully managed and only know reference counted objects.

Not exactly. The objects are managed, but not via reference counting.
They use a slightly more sophisticated garbage collector (and I have
heard the newer one for Java is actually quite good).
--
Rudy Velthuis (TeamB)

Rudy Velthuis (TeamB)

unread,
Nov 29, 2001, 1:14:03 PM11/29/01
to
In article <3c064249_1@dnews>, Frank Shearar says...

> No, I want to be able to say to the compiler "Listen here. I don't _want_
> you to call _AddRef/_Release." I don't like the compiler doing this magic stuff
> for me, or at least I'd like to be able to turn it off.

Why? Are you afraid the compiler will make a mistake? Do you think the
same about, say, strings, or dynamic arrays?

The first time I encountered reference counted interfaces (in D4), I
didn't trust them either. But they have never failed me, as long as I
only used the interface reference, and didn't mix.

> All I want to worry about with interfaces is that it means that the instance
> can respond to certain messages/execute certain methods. I don't want to
> have
> to worry about whether some variable is an interface variable or an object
> variable because that's not how I'm thinking about the objects. It's that
> slight mismatch between Delphi & my thinking that's causing friction, I
> suspect.

But as long as your _Release and _AddRef don't do anything, wouldn't
that be the same (except for the performance issue I mentioned)?



> As an example, you can do something like
>
> var
> O, Arb: TObject;
> begin
> O := TObject.Create;
> try
> Arb := O;
> finally
> O.Free;
> end;
> end;
>
> without even thinking about it. But with interfaces suddenly you have to
> ensure that your interfaces are nil by the end of the current scope, or
> you have to worry about how/when _AddRef/_Release are going to be called,
> etc.

Only if you still think in the old frame. In D6, it is made even simpler
to detach the interface from the implementation. That is IMO how
interfaces could be used at best.

But if you still want to use objects, that also export an interface for
some functionality, you can simply do as I said above: make _AddRef etc.
empty, only returning -1. You won't have to worry about them then.
--
Rudy Velthuis (TeamB)

Rudy Velthuis (TeamB)

unread,
Nov 29, 2001, 1:15:54 PM11/29/01
to
In article <3c06522e_2@dnews>, Frank Shearar says...

> Yes, you can do that - but I don't like reference counting :). At least, not
> in Delphi.

Come on now. Have you never used strings before? Have you ever worried
about their lifetime?
--
Rudy Velthuis (TeamB)

Rudy Velthuis (TeamB)

unread,
Nov 29, 2001, 1:22:46 PM11/29/01
to
In article <MPG.167097b58...@newsgroups.borland.com>, Rudy
Velthuis (TeamB) says...

> Of course that depends on the interface, and how many values it delivers
> at once. <g>

What I mean is the same as the difference between using the Pixels two-
dimensional array property, or the ScanLine concept, in graphics.

If your interface returns an entire row of a grid into a dynamic array,
or a buffer allocated by you, it can be quite fast, actually.
--
Rudy Velthuis (TeamB)

Iman L Crawford

unread,
Nov 29, 2001, 2:11:25 PM11/29/01
to
"Rudy Velthuis (TeamB)" <rvel...@gmx.de> wrote in
news:MPG.167099c85...@newsgroups.borland.com:
> Come on now. Have you never used strings before? Have you ever worried
> about their lifetime?

The difference is the usage of strings is almost the same as other "native"
types. For the most part you don't have to think about how they're
implemented, to use them.

Interfaces, as implemented in Delphi, force you to understand their
implementation to use them. The restriction of not mixing object and
interface references is artificial, it shouldn't be there. IIRC, in D6
they got rid of reference counting for interfaces of objects derived from
TComponent.

Frank Shearar

unread,
Nov 29, 2001, 3:02:07 PM11/29/01
to

"Greg Chapman" <g...@well.com> wrote in message
news:1hpa0usbiqgikmdu7...@4ax.com...

Ah! That makes sense! Now if only the compiler wouldn't call _Release and
_AddRef,
I'd be a very happy monkey. It's the helping hand that I can't stop helping
that
annoys me :)

Thanks, Greg, for your analysis.

frank


Frank Shearar

unread,
Nov 29, 2001, 3:08:56 PM11/29/01
to

"Joanna Carter" <joa...@btinternet.com> wrote in message
news:3c065b05$1_1@dnews...

> "Frank Shearar" <frank@spambounce.x> a écrit dans le message news:
> 3c06522e_2@dnews...
>
> > Yes, you can do that - but I don't like reference counting :). At least,
> not
> > in Delphi. That said, I'm prepared to admit that I'm being a bit
> > unreasonable
> > with regards to Delphi's implementation of the interface concept. I just
> > don't
> > like having to work around things - to write code such that I can avoid
> the
> > compiler inserting code I didn't ask for.
>
> Maybe it's because I use Interfaces all the time, but I can't see what you
> mean about having to work around things.
Well, the work-arounds only come in when you don't use reference counting.
Then
you have to make sure that your interface variables are all nil before they
go out of scope and whatnot.

> I don't 'work around' anything; I just use interfaces in the way they were
> designed and find that it makes design, coding and re-use much easier.

They were designed this way _in_Delphi_. Interfaces do make design and
coding and reuse much easier, which is why I want to use them - I just don't
want to be told "Thou shalt reference count thine interfaces Or Else", which
is pretty much the feeling I get from Delphi. And don't get me wrong - I
love Delphi deeply.

> The top and bottom of it is that interface pointers are automatically
> garbage collected and will stay in scope only as long as you have one
> reference to them. You don't have to free them explicitly, or even set
them
> to nil, all that is automatic.

IF you buy into reference counting. If you don't buy into reference counting
(and you must buy into it 100% unless you want nightmarish debugging
sessions)
then it seems you end up out in the cold.

> Could I just ask whether you are writing 'proper' OO code (no methods or
> fields outside of classes). If not then this can seem to complicate
matters.

If what you mean by 'proper' is what I think you mean, then yes. I don't
have methods or fields outside of classes, and I try to follow the examples
set by the PLoP people and whatnot.

frank


Franz-Leo Chomse

unread,
Nov 29, 2001, 3:39:25 PM11/29/01
to

>The difference is the usage of strings is almost the same as other "native"
>types. For the most part you don't have to think about how they're
>implemented, to use them.
>
>Interfaces, as implemented in Delphi, force you to understand their
>implementation to use them. The restriction of not mixing object and
>interface references is artificial, it shouldn't be there. IIRC, in D6
>they got rid of reference counting for interfaces of objects derived from
>TComponent.


its the same for strings. Long strings and generic containers don't
mix very well. Using the object reference for an object which
implements an interface is the same than typecasting long strings
to PChars.

Regards from Germany

Franz-Leo

Frank Shearar

unread,
Nov 29, 2001, 3:37:09 PM11/29/01
to
"Rudy Velthuis (TeamB)" <rvel...@gmx.de> wrote in message
news:MPG.16709958c...@newsgroups.borland.com...

> In article <3c064249_1@dnews>, Frank Shearar says...
>
> > No, I want to be able to say to the compiler "Listen here. I don't
_want_
> > you to call _AddRef/_Release." I don't like the compiler doing this
magic stuff
> > for me, or at least I'd like to be able to turn it off.
>
> Why? Are you afraid the compiler will make a mistake? Do you think the
> same about, say, strings, or dynamic arrays?
As Iman pointed out in another post, strings and dynamic arrays don't
require
you to have in-depth knowledge about how they work in order to use them.
Interfaces, of the non-reference-counted variety, do.

It's a question of what have I asked the compiler to do. Copy-on-write
semantics of strings, for example, do not change the behaviour of how
strings work (other than keeping resource usage significantly lower).
However, interfaces don't work like that. The compiler is not optimising
how the interfaces work - it's actually doing a bunch of stuff behind
the scenes; stuff that changes how your program behaves.

If you have O: TObject pointing at some object Obj, and Obj gets destroyed,
the programmer doesn't care that O is pointing at garbage if O isn't
used for the rest of the method. However, with interfaces you do. And
that split between how interfaces and objects work annoys the dickens
out of me.

> > All I want to worry about with interfaces is that it means that the
instance
> > can respond to certain messages/execute certain methods. I don't want to
> > have
> > to worry about whether some variable is an interface variable or an
object
> > variable because that's not how I'm thinking about the objects. It's
that
> > slight mismatch between Delphi & my thinking that's causing friction, I
> > suspect.
>
> But as long as your _Release and _AddRef don't do anything, wouldn't
> that be the same (except for the performance issue I mentioned)?

It would be - except that you get weird behaviour on occasion, as I
demonstrated with my ExhibitA and ExhibitB previously - Greg Chapman
explained the issue very clearly.

With your interface pointers, after all, if they're not nil then you're
going to get an access violation. And if there are temporary interface
references being generated (as per Greg's explanation), then again you're
going to get access violations, and they're going to occur for no apparent
reason unless you're intimately familiar with how interfaces work and how
the compiler treats them. Not that I'm suggesting that programmers should
be ignorant of what their environment is doing, mind you! It just seems
that this particular blip is a lot trickier than most.

> > without even thinking about it. But with interfaces suddenly you have to
> > ensure that your interfaces are nil by the end of the current scope, or
> > you have to worry about how/when _AddRef/_Release are going to be
called,
> > etc.
>
> Only if you still think in the old frame. In D6, it is made even simpler
> to detach the interface from the implementation. That is IMO how
> interfaces could be used at best.

Well, I'll take a copy of the work project home and try it out - I'm using
D5 at work but I've a copy of D6 at home. What exactly do you mean by
"old frame" though? Handling the lifetime of one's objects oneself?

> But if you still want to use objects, that also export an interface for
> some functionality, you can simply do as I said above: make _AddRef etc.
> empty, only returning -1. You won't have to worry about them then.

I know how to make interfaces not be reference counted. I just have issues
with working around the compiler's desire to clean up after interfaces.

frank


Rudy Velthuis (TeamB)

unread,
Nov 29, 2001, 4:02:33 PM11/29/01
to
In article <Xns91688763E...@207.105.83.65>,
ilcrawford.at.hotmail.dot.com (Iman L Crawford) says...

> Interfaces, as implemented in Delphi, force you to understand their
> implementation to use them.

I don't think so. They hide it.

> The restriction of not mixing object and
> interface references is artificial, it shouldn't be there.

I disagree. You can simply stop reference counting by deriving from the
right object.

> IIRC, in D6 they got rid of reference counting for interfaces of objects derived from
> TComponent.

The same in D5 and D4, IIRC. They just surface a few more interfaces.
--
Rudy Velthuis (TeamB)

Rudy Velthuis (TeamB)

unread,
Nov 29, 2001, 4:05:59 PM11/29/01
to
In article <3c069c79_1@dnews>, Frank Shearar says...

> As Iman pointed out in another post, strings and dynamic arrays don't
> require
> you to have in-depth knowledge about how they work in order to use them.
> Interfaces, of the non-reference-counted variety, do.

Ah, but if they are non-reference counted, you can simply use them as if
they were objects. But why have the non-reference counted variety at
all? I'd only do that for objects that are managed by something else,
i.e. by ownership, like components.



> If you have O: TObject pointing at some object Obj, and Obj gets destroyed,
> the programmer doesn't care that O is pointing at garbage if O isn't
> used for the rest of the method. However, with interfaces you do. And
> that split between how interfaces and objects work annoys the dickens
> out of me.

It's like using PChars to access strings. You must be aware of the
implications as well.
--
Rudy Velthuis (TeamB)

Iman L Crawford

unread,
Nov 29, 2001, 4:38:22 PM11/29/01
to
Franz-Leo Chomse <franz-le...@samac.de> wrote in
news:947d0usdermp4rufq...@4ax.com:
> its the same for strings. Long strings and generic containers don't
> mix very well. Using the object reference for an object which
> implements an interface is the same than typecasting long strings
> to PChars.

I'd have to disagree. You're typecasting between two different things, and
even then it's pretty easy, most of the time you just typecast it. I like
how Java handles interface/object references, you don't have to think about
their implementation for general use.

Bjørge Sæther

unread,
Nov 29, 2001, 6:40:33 PM11/29/01
to
"Rudy Velthuis (TeamB)" <rvel...@gmx.de> skrev i melding
news:MPG.167095421...@newsgroups.borland.com...

Well spoken ;-)
One could possibly add that other arguments for using interfaces may be
x-platform or for defining "module interfaces" (no class definition overhead
and fragile compatibility issues).

--
Bjørge Sæther
bjo...@itte.no

Bjørge Sæther

unread,
Nov 29, 2001, 6:55:35 PM11/29/01
to
"Rudy Velthuis (TeamB)" <rvel...@gmx.de> skrev i melding
news:MPG.16709b5d2...@newsgroups.borland.com...

Oh, yes, performance isn't an issue *that* often. I "invented" the
pointer-to-interface style of programming when I was working with data
objects - where you typically paint one row of data by iterating through
field descriptors, retrieving & formatting one field value at a time. The
result is very much like writing an entire application based on variant
variables - it adds quite some overhead when doing sorting, heavy displaying
or any other kind of access at field level. if you do a "for 1:=0 to n do
..." and every iteration involves interface copying, the maximum throughput
is substantially reduced.
I solved the interface retrieval by storing the interface in a pointer
variable upon creation:

pIMyIntf = ^IMyIntf;
IMyIntf = interface
function _IMyIntf: pIMyIntf;
end;

(_AddRef, etc. left out)

TMyClass = class(TObject, IMyIntf)
'[GUID]'
private
FMyIntf:
protected
procedure InitInterfaces; virtual;
public
constructor create;
function _IMyIntf: pIMyIntf;
end;

---

FMyIntf:
protected

constructor TMyClass.create;
begin
InitInterfaces;
end;

procedure TMyClass.InitInterfaces;
var
Intf: IMyIntf;
begin
Intf:=Self;
FIMyIntf:=Pointer(Intf);
end;

function TMyClass._IMyIntf: pIMyIntf;
begin
result:=@FIMyIntf;
end;

...and gone was interface refcounting, querying & copying...;-)

...unless I don't do a:

var
Intf: pIMyIntf;
begin
...
With Intf^ do begin

Bjørge Sæther

unread,
Nov 29, 2001, 7:01:25 PM11/29/01
to
"Joanna Carter" <joa...@btinternet.com> skrev i melding
news:3c065b05$1_1@dnews...

> "Frank Shearar" <frank@spambounce.x> a écrit dans le message news:
> 3c06522e_2@dnews...
>
> > Yes, you can do that - but I don't like reference counting :). At least,
> not
> > in Delphi. That said, I'm prepared to admit that I'm being a bit
> > unreasonable
> > with regards to Delphi's implementation of the interface concept. I just
> > don't
> > like having to work around things - to write code such that I can avoid
> the
> > compiler inserting code I didn't ask for.
>
> Maybe it's because I use Interfaces all the time, but I can't see what you
> mean about having to work around things.
>
> I don't 'work around' anything; I just use interfaces in the way they were
> designed and find that it makes design, coding and re-use much easier.

You may have to work around if you need maximum speed.

> The top and bottom of it is that interface pointers are automatically
> garbage collected and will stay in scope only as long as you have one
> reference to them. You don't have to free them explicitly, or even set them
> to nil, all that is automatic.

But this means that there is an _AddRef / _Release pair of calls upon every
single little reference. I like this just as little as I would like it if all
verieble types in Delphi were reference counted like strings.

> Could I just ask whether you are writing 'proper' OO code (no methods or
> fields outside of classes). If not then this can seem to complicate
matters.

It's another way of thinking, that's all.

--
Bjørge Sæther
bjo...@itte.no

Bjørge Sæther

unread,
Nov 29, 2001, 7:10:46 PM11/29/01
to
"Rudy Velthuis (TeamB)" <rvel...@gmx.de> skrev i melding
news:MPG.1670c1a02...@newsgroups.borland.com...

> In article <3c069c79_1@dnews>, Frank Shearar says...
>
> > As Iman pointed out in another post, strings and dynamic arrays don't
> > require
> > you to have in-depth knowledge about how they work in order to use them.
> > Interfaces, of the non-reference-counted variety, do.
>
> Ah, but if they are non-reference counted, you can simply use them as if
> they were objects. But why have the non-reference counted variety at
> all? I'd only do that for objects that are managed by something else,
> i.e. by ownership, like components.

But Rudy, can't you see that the problem is that you need to be almost as
cautious even if refcounting is "deactivated", because the methods are
actually called. Interface methods work in a "two-step" manner, where one
needs a valid reference much like with virtual methods. One should simply
have an option for disabling this behaviour for a class. Just leaving out the
compiler magic. No big deal.

--
Bjørge Sæther
bjo...@itte.no

Rocco Barbaresco

unread,
Nov 30, 2001, 2:23:38 AM11/30/01
to
> One should simply have an option for disabling this behaviour for a class. Just leaving out the
>compiler magic. No big deal.

Completely agree. We had this problem too, and spent a lot of time
looking for the cause of an AV.

Bye, Rocco.

Joanna Carter

unread,
Nov 30, 2001, 4:49:32 AM11/30/01
to
"Frank Shearar" <frank@spambounce.x> a écrit dans le message news:
3c0695de_1@dnews...

> Well, the work-arounds only come in when you don't use reference counting.
> Then
> you have to make sure that your interface variables are all nil before
they
> go out of scope and whatnot.

The only real problems that I have found is when I use something that
derives from TComponent; this usually means that Delphi can free the
component before I get a chance to nil an interface reference.

The way around this is to ensure that the interface reference is notified in
the destructor of the component.

Is this the kind of thing that you are talking about?

I only tend to use non-reference counted objects for UI on a Form; mostly
this entails using the Observer pattern and, of course after the observer is
freed by Delphi, you have an invalid reference to the Observer in the list
of observers in the Subject.

However, if you stick to the idea that business objects (reference counted
interfaces) are meant to be responsible for the creation and destruction of
UI elements (non reference counted components), then this problem goes away.

The cause of most grief in this area is allowing business objects to be
created after the form that displays them has already been created.

Comments?

> If what you mean by 'proper' is what I think you mean, then yes. I don't
> have methods or fields outside of classes, and I try to follow the
examples
> set by the PLoP people and whatnot.

II hope you didn't think I was insulting your abilities, but it is not
always possibe to assume technique from e-mail <g>

Joanna


Frank Shearar

unread,
Nov 30, 2001, 5:11:26 AM11/30/01
to

"Joanna Carter" <joa...@btinternet.com> wrote in message
news:3c07561f$1_2@dnews...

> "Frank Shearar" <frank@spambounce.x> a écrit dans le message news:
> 3c0695de_1@dnews...
>
> > Well, the work-arounds only come in when you don't use reference
counting.
> > Then
> > you have to make sure that your interface variables are all nil before
> they
> > go out of scope and whatnot.
>
> The only real problems that I have found is when I use something that
> derives from TComponent; this usually means that Delphi can free the
> component before I get a chance to nil an interface reference.
>
> The way around this is to ensure that the interface reference is notified
in
> the destructor of the component.
>
> Is this the kind of thing that you are talking about?

Not really - I've not run into problems with TComponent descendants, but
that's because I'm not working with anything even vaguely visual at the
moment. I'm talking about having to do stuff like

var
I: INonReferenceCounted;
O: TWhatever;
begin
O := TWhatever.Create;
try
I := O;
finally
I := nil; // the workaround
O.Free;
end;
end;

> I only tend to use non-reference counted objects for UI on a Form; mostly
> this entails using the Observer pattern and, of course after the observer
is
> freed by Delphi, you have an invalid reference to the Observer in the list
> of observers in the Subject.

Yes, GoF specifically mention this in "Design Patterns", on p. 297.

> However, if you stick to the idea that business objects (reference counted
> interfaces) are meant to be responsible for the creation and destruction
of
> UI elements (non reference counted components), then this problem goes
away.

This will be true generally, not so? That is, if your reference counted
objects
create non reference counted objects.

What exactly do you mean by "business objects ... are meant to be
responsible
for the creation and destruction of UI elements"? Do you mean that your,
say,
Person object will create a form (or whatever) for the user to edit?

> The cause of most grief in this area is allowing business objects to be
> created after the form that displays them has already been created.
>
> Comments?

I'm busy rebuilding the company OPF from scratch, so I've not gotten as
far as anything even vaguely resembling a UI. My hindbrain's whispering
something at me about the interaction between UI stuff and domain objects,
but it's not talking loud enough yet for me to hear.

> II hope you didn't think I was insulting your abilities, but it is not
> always possibe to assume technique from e-mail <g>

Rest assured, no insult was taken :)

frank


Joanna Carter

unread,
Nov 30, 2001, 6:12:39 AM11/30/01
to
"Frank Shearar" <frank@spambounce.x> a écrit dans le message news:
3c075b51_1@dnews.

> Not really - I've not run into problems with TComponent descendants, but
> that's because I'm not working with anything even vaguely visual at the
> moment. I'm talking about having to do stuff like
>
> var
> I: INonReferenceCounted;
> O: TWhatever;
> begin
> O := TWhatever.Create;
> try
> I := O;
> finally
> I := nil; // the workaround
> O.Free;
> end;
> end;

What you are doing here is definitely dangerous and just the same as using
two pointers to one object.

Because O was created as an ordinary object, then I was pointed to the same
address; this means that as soon as O was freed, I was invalid because they
point to the same address.

However, I am at a loss to know why you would use an interface that is
designed to be implemented by a non_reference counted class?

What you are essentially doing is a very complicated way of creating a class
that might support an Interface, but acts just like another object pointer.

As has been said before, you should only use interface pointers to create
and reference instances of classes that support an interface. The only
exception would normally be TComponent derivatives.

> This will be true generally, not so? That is, if your reference counted
> objects
> create non reference counted objects.

If they do create no-counted objects then must clean them up.

> What exactly do you mean by "business objects ... are meant to be
> responsible
> for the creation and destruction of UI elements"? Do you mean that your,
> say,
> Person object will create a form (or whatever) for the user to edit?

That may happen, but I usually use Model View Presenter, and then it tends
to be a Presenter or Manager that is responsible for UI instantiation.

Joanna


Frank Shearar

unread,
Nov 30, 2001, 6:50:10 AM11/30/01
to
"Joanna Carter" <joa...@btinternet.com> wrote in message
news:3c07699f_1@dnews...

> "Frank Shearar" <frank@spambounce.x> a écrit dans le message news:
> 3c075b51_1@dnews.
> > Not really - I've not run into problems with TComponent descendants, but
> > that's because I'm not working with anything even vaguely visual at the
> > moment. I'm talking about having to do stuff like
> >
> > var
> > I: INonReferenceCounted;
> > O: TWhatever;
> > begin
> > O := TWhatever.Create;
> > try
> > I := O;
> > finally
> > I := nil; // the workaround
> > O.Free;
> > end;
> > end;
>
> What you are doing here is definitely dangerous and just the same as using
> two pointers to one object.

I agree with the 2nd part of the sentence. As to begin dangerous, I don't
think so - it's common practice to declare a temporary variable:

Let O be a TObjectList of TObjectLists (so we have a sort've ragged array
effect). If you want to reference the 4th object of the 3rd list you're soon
going to tire of typing out TFoo(TObjectList(O[2])[3]) or whatever, so you
declare Foo: TFoo and say Foo := TFoo(TObjectList(O[2])[3]). That's the
equivalent of what I was trying to illustrate in the above code. Sure,
with statements can do the same thing, but with statements can also
introduce
tricky bugs when refactoring code. (Of course, one should have unit tests in
place before refactoring, but that's another issue.)

> Because O was created as an ordinary object, then I was pointed to the
same
> address; this means that as soon as O was freed, I was invalid because
they
> point to the same address.

Yes. But if you don't use I after that, what's the big deal? You're only
supposed to put the finally after you're finished dealing with O, and that
implicitly means that you're finished dealing with I. It's the same as
declaring an object reference and never assigning anything to it - as soon
as you try to dereference the variable you're going to have an access
violation.

> However, I am at a loss to know why you would use an interface that is
> designed to be implemented by a non_reference counted class?

I don't like reference counting in Delphi. It feels too much like a
tacked-on
piece of functionality. It does not fit with the way the rest of Delphi
works.
As evidence, consider the fact that you have to pay serious attention to
what
creates what and which instances are reference counted and which not.
Reference counting in Java and Smalltalk I'm OK with - the whole environment
is built around reference counting.

> What you are essentially doing is a very complicated way of creating a
class

> that might support an Interface, but acts just like another object
pointer.

Yes. That's exactly what I want. I want some classes to speak to the
instance
in one way, and other classes to speak to it another way.

> As has been said before, you should only use interface pointers to create
> and reference instances of classes that support an interface. The only
> exception would normally be TComponent derivatives.

Sure. My code is a sketch. I left out all sorts of flimflam like
"TWhatever = class(TObject, INonReferenceCounted)".

> > This will be true generally, not so? That is, if your reference counted
> > objects
> > create non reference counted objects.
>
> If they do create no-counted objects then must clean them up.

Yes. I felt that that was implicit :) Having non reference counted instances
that created reference counted instances would, of course, mean that come
cleanup time the reference counted instances might already have died, and
the dying instances' references would hence be dangling.

frank


Rocco Barbaresco

unread,
Nov 30, 2001, 7:42:30 AM11/30/01
to
<.....>

>What you are doing here is definitely dangerous and just the same as using
>two pointers to one object.
>

Well, I agree with you when you say it's dangerous, but that's exactly
the problem.
I don't want that a simple I:= nil calls a method of the object
pointed by the old value of I. That's all.
I think that's a quite reasonable request.
Bye, Rocco.

Rudy Velthuis (TeamB)

unread,
Nov 30, 2001, 8:06:31 AM11/30/01
to
In article <3c06ce91$1_1@dnews>, Bjørge Sæther says...

> But Rudy, can't you see that the problem is that you need to be almost as
> cautious even if refcounting is "deactivated", because the methods are
> actually called.

What happens if they are called? They don't do anything, or access any
field.

> Interface methods work in a "two-step" manner, where one
> needs a valid reference much like with virtual methods. One should simply
> have an option for disabling this behaviour for a class. Just leaving out the
> compiler magic. No big deal.

I'm not sure it isn't.
--
Rudy Velthuis (TeamB)

Rocco Barbaresco

unread,
Nov 30, 2001, 8:13:58 AM11/30/01
to
>
>> But Rudy, can't you see that the problem is that you need to be almost as
>> cautious even if refcounting is "deactivated", because the methods are
>> actually called.
>
>What happens if they are called? They don't do anything, or access any
>field.
>

You could get an AV!
That's the problem.

Rocco

Rudy Velthuis (TeamB)

unread,
Nov 30, 2001, 8:11:33 AM11/30/01
to
In article <3c07337e...@newsgroups.borland.com>, Rocco Barbaresco
says...

If you had an AV, you either did something wrong, or actually mixed both
kinds of access.

The same kind of AV can happen when you make mistakes in managing the
lifetime of your classes, or if you have multiple references to the same
object.

IOW: that is a design problem. Using reference counting (and only that!)
actually relieves you of some of these hassles.

You can even access your objects directly, as long as you make sure they
are not freed before all references are lost. The same is true for
simple, non-interfaced objects.
--
Rudy Velthuis (TeamB)

Rudy Velthuis (TeamB)

unread,
Nov 30, 2001, 8:15:47 AM11/30/01
to
In article <3c07699f_1@dnews>, Joanna Carter says...

> What you are doing here is definitely dangerous and just the same as using
> two pointers to one object.

Indeed!

--
Rudy Velthuis (TeamB)

Rudy Velthuis (TeamB)

unread,
Nov 30, 2001, 4:09:34 PM11/30/01
to
In article <3c0785c3...@newsgroups.borland.com>, Rocco Barbaresco
says...

> >What happens if they are called? They don't do anything, or access any
> >field.
> >
> You could get an AV!

I agree you could get one if the object was freed before. But IMO that
is just as much a design problem as having multiple references, and
using free on all of them.
--
Rudy Velthuis (TeamB)

Jan Nordén

unread,
Dec 3, 2001, 2:02:09 AM12/3/01
to
As has been stated prevoiusly in this group, it the underlying object has
been freed, that you will get an AV when _release is
automagically called when the interface variable goes out of scope (sonce
the VTABLE in no onger there).

"Rudy Velthuis (TeamB)" <rvel...@gmx.de> wrote in message

news:MPG.167052851...@newsgroups.borland.com...
> In article <3c055e7f_2@dnews>, Frank Shearar says...
>
> > > If you're not implementing reference counting, then the call's to
_AddRef
> > > and _Release don't (really "shouldn't") have any affect.
>
> > Agreed. But the compiler magic still does its thing calling _AddRef and
> > _Release.
>
> And in what way is that bad? Are you worried about performance?
> --
> Rudy Velthuis (TeamB)


Jan Nordén

unread,
Dec 3, 2001, 2:58:18 AM12/3/01
to
I find this thread strange, not for the difference of opinions, but in the
failure by many participants to see the whole picture (independently of
which part they happen to like). This leads to statements like "this is the
way it is" and "interfaces work that way", rather than "I think this
combination of language design decisions would have been better" vs "I like
the Delphi choices".

The implementation of interfaces in Delphi does mix two issues that could be
separate, that of providing an interface to an object, and that of providing
a limited type of garbage collection (reference counting).

There is no reason whatsoever to restrict refcounting to interfaces, nor is
there any reason to always refcount interfaces.

There are many uses for plain refcounted objects, and having to define an
interface just to get refcounting seems like a roundabout way of doing
things.

In the same way there are uses for non-lifetime controlling interfaces,
specifically when providing typed access to things with owners, e.g. visual
components,
domain objects owned by a cache, etc. Having to take special precautions
here not needed for regular object references is also inconvenient and
surprising to some.

The basic issue in the last statement is the following:

For plain object references it is OK to hold an invalid reference as long as
you don't dereference it. You can write:

var
A, B: TXX;
begin
A := TXX.Create;
B := A;
A.Free;
end;

Note that at the end of this method it is not only B that points to a
nonexisting object, so does A, and without ill effects.

You may think this is a good or a bad thing but most users are used to it.

However, with interfaces an invalid reference will always be dereferenced
when the variable goes out of scope:

var
A: TXX;
B: ISortable; // Non-refcounted interface implemented by A.
begin
A := TXX:Create;
B := A;
A.Free;
end; // exception here when B._release is called

Again, you may think this is better or worse, but it is definitely different
from the behaviour above.


"Rudy Velthuis (TeamB)" <rvel...@gmx.de> wrote in message

news:MPG.1671a3ead...@newsgroups.borland.com...

Bjørge Sæther

unread,
Dec 3, 2001, 11:40:51 AM12/3/01
to
"Jan Nordén" <jan.n...@boldsoft.com> skrev i melding
news:3c0b309e_1@dnews...

> I find this thread strange, not for the difference of opinions, but in the
> failure by many participants to see the whole picture (independently of
> which part they happen to like). This leads to statements like "this is
the
> way it is" and "interfaces work that way", rather than "I think this
> combination of language design decisions would have been better" vs "I like
> the Delphi choices".
>
> The implementation of interfaces in Delphi does mix two issues that could
be
> separate, that of providing an interface to an object, and that of
providing
> a limited type of garbage collection (reference counting).
>
> There is no reason whatsoever to restrict refcounting to interfaces, nor is
> there any reason to always refcount interfaces.
>
> There are many uses for plain refcounted objects, and having to define an
> interface just to get refcounting seems like a roundabout way of doing
> things.
>
> In the same way there are uses for non-lifetime controlling interfaces,
> specifically when providing typed access to things with owners, e.g. visual
> components,
> domain objects owned by a cache, etc. Having to take special precautions
> here not needed for regular object references is also inconvenient and
> surprising to some.

Well written, my 100% support !

--
Bjoerge Saether
Asker, Norway
bjorge@hahaha_itte.no (remve the obvious)


Rudy Velthuis (TeamB)

unread,
Dec 4, 2001, 7:36:36 AM12/4/01
to
In article <3c0b309e_1@dnews>, Jan Nordén says...

> The implementation of interfaces in Delphi does mix two issues that could be
> separate, that of providing an interface to an object, and that of providing
> a limited type of garbage collection (reference counting).
>
> There is no reason whatsoever to restrict refcounting to interfaces, nor is
> there any reason to always refcount interfaces.

That is true. But don't forget that Borland interfaces started their
life as COM IUnknowns, and these require AddRef and Release to be called
in time. Borland decided to make our lives easier, and take care of the
reference counting for us.

Interfaces per se don't need it. The OP implementation can't be changed
to be independent of it anymore, I guess.

Perhaps Borland might come up with a new mechanism that doesn't require
it.
--
Rudy Velthuis (TeamB)

Rudy Velthuis (TeamB)

unread,
Dec 4, 2001, 7:39:40 AM12/4/01
to
In article <3c0b2375_1@dnews>, Jan Nordén says...

> As has been stated prevoiusly in this group, it the underlying object has
> been freed, that you will get an AV when _release is
> automagically called when the interface variable goes out of scope (sonce
> the VTABLE in no onger there).

Yes, I know, and I even replied to one of these statements.

Still, letting that happen is IMO something the design of the code which
uses interfaces should have prevented. It is IMO in the same class as
having multiple references to one object, and calling free on all of

Jan Nordén

unread,
Dec 5, 2001, 9:15:19 AM12/5/01
to
It could be changed quite easily, thogh I doubt that Borland would put it on
the list of priorities. I am also not sure that it would increase or reduce
confusion for the majority of usesr:-).

Anyway, an example of a possible implementation would be to add a directive
"refcounted" on classes and interfaces.

IUnknown would of course be refcounted.

Defining a interface as refcounted would imply that iterface variables of
this type would have the current behaviour, i.e. _addref/_release, and
hidden try/finally where needed.

In the same way refcounted on a class would mean that variables of the class
type would behave in the same way.


"Rudy Velthuis (TeamB)" <rvel...@gmx.de> wrote in message

news:MPG.1676e1c02...@newsgroups.borland.com...

0 new messages