RED MONKEY
RED MONKEY

Reputation: 3153

When implementing an interface in Delphi, does it matter if the implementation methods are not in the public section?

Given the interface below:

ITest = interface ['guidhere']
  procedure TestMethod;
end;

Is there any reason to have TestMethod() declared as public in the implementation class? I have put it in both the private and protected sections and it does not seem to make a difference. I am just wondering if there are any guidelines, from a design perspective (or any perspective really), that make the public section the correct section to implement the method in.

Upvotes: 6

Views: 1436

Answers (2)

Rob Lambden
Rob Lambden

Reputation: 2293

I appreciate this is an old question, but the answer is no longer accurate.

I am using Rio, and from the documentation:

All members of an interface are public. Visibility specifiers and storage specifiers are not allowed. (But an array property can be declared as default.)

which is indeed what I observe. An interface defitnion will not allow protected, private or public to be specified.


Edit: To incorporate comments to this answer

At the time of writing the compiler does not enforce any level of visibility on the methods which implement the interface. The methods will be callable through either the interface (interface reference) or through the class (object instance).

As the interface definition insists that all methods are public, when called through an interface reference the implementing methods are public regardless of how they are defined in the implementing class. As a reference to the interface can be obtained from the object then they are callable from the object, although the caller may have to obtain the interface reference first.

Given that the implementing methods are callable as public through the interface you should consider how helpful it is to not make them public in your class. Restricting the visibility of the methods in the class when they are public in the interface seems to me to be making the code less clear, but other opinions are available!

One of the comments mentioned delegation of the interface. This seems to me to be a distraction as it simply means that when the object retruns the interface reference it returns the reference from the delgated object (which could itself delegate the interface) and ultimately it is the methods of that object whaich are called.

So any class which implements an interface makes the methods which implement the interface available as public when called through the interface.

Upvotes: -2

Johan
Johan

Reputation: 76670

does it matter if the implementing methods are not in the public section?

As far as the compiler is concerned. It makes no difference.

That being said. Private methods will still be private, even if you can access them through the interface.

unit unit1;
....
IItest = interface
  ['{A3D5FEB6-8E29-4EA8-8DC9-7988294EFA65}']
  procedure Test;
end;

TTest = class(TInterfacedObject, IItest)
private
  procedure Test;
end;

unit unit2;
....
var
  TestT: TTest;
  TestI: ITest;
begin
  TestT:= TTest.Create;
  TestI:= TTest.Create;
  TestT.Test;  //will not compile.
  TestI.Test;  //works.

The reason for this is that the interface simply has a list of pointers to methods in its VMT. The definition of the method is given in the interface definition.
The compiler only checks if the signatures match.
It does not check the visibility of the method.

As per Allen's comment this is a deliberate design:

Making the methods private or protected will ensure that you can only access them through the interface. This is a way to enforce a usage contract for the intended use of the object.

Note that this is not an error, or even a bad thing.
Properties can give 'access' to private methods as well:

property Items[index: integer] read GetItem write SetItem;  

Here GetItem and SetItem are often private.
This forces you to access the Items using the property.
When using properties the implementing methods are protected (or worse :-) as a rule. The same logic applies to both properties and interfaces.

More so for interfaces, because if you mix interface access and regular access you'll run into reference counting issues.

Clean code
Note that you can have as many visibility sections in a class header as you like.
This way you can put all the interfaced methods in one part and all the non-interfaced methods in another.

TTest = class(TInterfacedObject, I1, I2)
//I1 methods
private
  ... private I1 methods here...
protected
  .. more I1 methods
//I2 methods
private
  .. some I2 methods
protected
  ..more I2 methods     
//TTest methods
private
  //data members
public
  constructor Create;
  destructor Destroy; override;
end;

That way it's as clear as can be what's what.

Upvotes: 6

Related Questions