Discussion:
Three questions about interfaces...
(too old to reply)
Ikke
2011-01-25 21:31:27 UTC
Permalink
Hi everybody,

There's something I don't really understand about interfaces. Suppose you
have the following situation:

an interface 'ISavable' (defined in a unit)
-----
type
ISavable = Interface(IInterface)
// Properties and their functions
function Load : boolean;
function Save : boolean;
end;

function Save : boolean;
begin
result := true;
end;
-----

a class implementing said interface (defined in a second unit)
-----
TWorld = Class(TInterfacedObject, ISavable)
private
{ Private declarations }
function Save : boolean;
public
{ Public declarations }
end;

function TWorld.Save : boolean;
begin
result := false;
end;
-----

and some code, creating a world in need of saving (in a third unit)
-----
procedure TForm1.SaveWorldClick(Sender: TObject);
var
world : ISavable;
begin
world := TWorld.Create;
if (world.Save) then
begin
ShowMessage('The world is saved!');
end
else
begin
ShowMessage('The world is lost!');
end;
FreeAndNil(world);
end;
-----

My first question: is this the proper way (in the interface) to provide a
default implementation? I suspect not, because if it were a class, I'd
need to prepend the function name with the class name.

Second question: the result of this little procedure is a showmessage
which tells me 'the world is lost'. How on earth can the Save function be
called from within the form, since it's private in the unit containing
the World class? Is it because the Save function is defined in the
interface, in other words, can I assume that private/public no longer
matters here?

Third, and last question: the FreeAndNil statement to destroy the world
object gives me a nice AccessViolation, but I can't see why. If world is
properly created, surely I should be able to destroy it?

Coming from a Java background, I fear I'm missing several parts of the
Delphi interface puzzle here - would anybody please be so kind as to
explain them to me? Thanks ever so much!

Best regards,

Ikke
Hans-Peter Diettrich
2011-01-26 03:43:59 UTC
Permalink
Post by Ikke
My first question: is this the proper way (in the interface) to provide a
default implementation?
No.
Post by Ikke
I suspect not, because if it were a class, I'd
need to prepend the function name with the class name.
Interfaces are *abstract*, and can not have any implementation.
A procedural type also does not have a default implementation...
Post by Ikke
Second question: the result of this little procedure is a showmessage
which tells me 'the world is lost'. How on earth can the Save function be
called from within the form, since it's private in the unit containing
the World class? Is it because the Save function is defined in the
interface, in other words, can I assume that private/public no longer
matters here?
Everything declared in the interface is public.
Post by Ikke
Third, and last question: the FreeAndNil statement to destroy the world
object gives me a nice AccessViolation, but I can't see why. If world is
properly created, surely I should be able to destroy it?
Interfaced objects are destroyed automatically, just like in Java. You
can set an interface reference to Nil, and when this was its last
reference, the underlying object is destroyed.

The Delphi implementation of FreeAndNil can result in much trouble, if
you call it with anything but TObject descendants :-(
Post by Ikke
Coming from a Java background, I fear I'm missing several parts of the
Delphi interface puzzle here - would anybody please be so kind as to
explain them to me? Thanks ever so much!
Unlike Java, the Delphi implementation uses reference counting for the
lifetime management of interfaces and dynamic strings or arrays.

DoDi
Ikke
2011-01-26 18:20:46 UTC
Permalink
Hi Hans-Peter,

Thanks for answering my questions!

<snip>
Post by Hans-Peter Diettrich
Post by Ikke
Second question: the result of this little procedure is a showmessage
which tells me 'the world is lost'. How on earth can the Save
function be called from within the form, since it's private in the
unit containing the World class? Is it because the Save function is
defined in the interface, in other words, can I assume that
private/public no longer matters here?
Everything declared in the interface is public.
In that case, I do find it strange that the compiler doesn't warn you
about putting functions/procedures in the private section. I understand
that they remain public, but it's a bit confusing if you're looking at
one unit only, without having a look at the interface at the same time I
guess...
Post by Hans-Peter Diettrich
Post by Ikke
Third, and last question: the FreeAndNil statement to destroy the
world object gives me a nice AccessViolation, but I can't see why. If
world is properly created, surely I should be able to destroy it?
Interfaced objects are destroyed automatically, just like in Java. You
can set an interface reference to Nil, and when this was its last
reference, the underlying object is destroyed.
The Delphi implementation of FreeAndNil can result in much trouble, if
you call it with anything but TObject descendants :-(
I'll keep it in mind.

Thanks again for your explanation, you've helped me a lot!

Ikke
Maarten Wiltink
2011-01-26 22:30:22 UTC
Permalink
Post by Ikke
Post by Hans-Peter Diettrich
Post by Ikke
Second question: the result of this little procedure is a showmessage
which tells me 'the world is lost'. How on earth can the Save
function be called from within the form, since it's private in the
unit containing the World class? Is it because the Save function is
defined in the interface, in other words, can I assume that
private/public no longer matters here?
Everything declared in the interface is public.
In that case, I do find it strange that the compiler doesn't warn you
about putting functions/procedures in the private section. I understand
that they remain public, but it's a bit confusing if you're looking at
one unit only, without having a look at the interface at the same time I
guess...
Everything in the interface is public _when you look at it through the
interface_. If you go through a classtype reference, the normal rules
for visibility apply.

In fact, if you go through an interface reference, the normal rules for
visibility apply, too. For that case the rule is : everything's public.

There are different kinds of interfaces. Some are related to the
meaning of the class itself, and then it makes sense to have the methods
in the interface be public in the class, too. Other interfaces are not
related to the class but for example make it useable with some outside
system, and then the class need not admit to those methods except through
the interface.

Your persistence scheme is of the latter type. It is not inherent in
the world that it can be saved (or restored from tape later). The Save
method is germane to the interface but nobody but the persistence layer
should be using it, and it does not care about the class; it will always
use the interface. So Save being private in the class is correct.

Groetjes,
Maarten Wiltink
Hans-Peter Diettrich
2011-01-27 00:43:00 UTC
Permalink
Post by Ikke
In that case, I do find it strange that the compiler doesn't warn you
about putting functions/procedures in the private section.
There exists no need that the methods, which implement the interface,
are callable from somewhere else. You can give their implementations
whatever visibility looks okay to you. The same interface can be
implemented in multiple classes, in different ways and with different
visibility of the methods.

DoDi

Loading...