Why we need interfaces in Delphi.

Objects are normally accessed by an object reference. Interface reference is a different method to access an object’s functionality. A simple question – why do we need interface references at all, why can’t we use object references everywhere?
There are several reasons to use interface references instead of object references, but most important of them (at least historically) is accessing an object created in a different program module.
Let us consider a simple example – an object is created in .dll module and consumed in .exe module.
The TMathObject class implements Square and Cube functions on the FOperand field; we start with the following naive code:

unit MathUnit;

interface

type
  TMathObject = class
  private
    FOperand: Double;
  public
    function Square: Double;
    function Cube: Double;
    property Operand: Double read FOperand write FOperand;
  end;

implementation

function TMathObject.Square: Double;
begin
  Result:= Sqr(FOperand);
end;

function TMathObject.Cube: Double;
begin
  Result:= Sqr(FOperand) * FOperand;
end;

end.

We want to create and destroy TMathObject instances in dll module:

library MathDll;

uses
  MathUnit in 'MathUnit.pas';

function CreateObject: TMathObject;
begin
  Result:= TMathObject.Create;
end;

procedure FreeObject(Obj: TMathObject);
begin
  Obj.Free;
end;

exports
  CreateObject, FreeObject;

{$R *.res}

begin
end.

and use an instance of TMathObject in exe module:

program MathTest;

{$APPTYPE CONSOLE}

uses
  MathUnit in 'MathUnit.pas';

function CreateObject: TMathObject; external 'MathDll.dll';
procedure FreeObject(Obj: TMathObject); external 'MathDll.dll';

var
  MathObj: TMathObject;

begin
  MathObj:= CreateObject;
  MathObj.Operand:= 2;
  Writeln('Square = ', MathObj.Square:3:2, '; Cube = ', MathObj.Cube:3:2);
  FreeObject(MathObj);
  Write('Press ''Enter'' key ... ');
  Readln;
end.

If you compile the above example you can see it works, but TMathObject implementation (MathUnit.pas) is duplicated in both program modules (MathTest.exe and MathDll.dll), and that is not just a waste of program memory.
One of the main reasons to split a program into program modules is a possibility to modify the modules separately; for example to modify and deploy a different .dll version while keeping an .exe module intact. In the above example the implementation of TMathObject is a contract that both sides (exe and dll) should adhere, so the implementation of TMathObject can’t be changed in dll module only.
We need a different form of contract that does not include an object’s implementation. A possible solution is to introduce a base class containing virtual abstract methods only:

unit BaseMath;

interface

type
  TBaseMathObject = class
  protected
    function GetOperand: Double; virtual; abstract;
    procedure SetOperand(const Value: Double); virtual; abstract;
  public
    function Square: Double; virtual; abstract;
    function Cube: Double; virtual; abstract;
    property Operand: Double read GetOperand write SetOperand;
  end;

implementation

end.

Note that we can’t access FOperand field directly now because it is a part of TMathObject implementation that should be hidden in .dll module, so we introduce getter (GetOperand) and setter (SetOperand) virtual methods.
Now we inherit a class that implements virtual methods from TBaseMathObject.

unit MathUnit;

interface

uses BaseMath;

type
  TMathObject = class(TBaseMathObject)
  private
    FOperand: Double;
  protected
    function GetOperand: Double; override;
    procedure SetOperand(const Value: Double); override;
  public
    function Square: Double; override;
    function Cube: Double; override;
  end;

implementation

function TMathObject.GetOperand: Double;
begin
  Result:= FOperand;
end;

procedure TMathObject.SetOperand(const Value: Double);
begin
  FOperand:= Value;
end;

function TMathObject.Square: Double;
begin
  Result:= Sqr(FOperand);
end;

function TMathObject.Cube: Double;
begin
  Result:= Sqr(FOperand) * FOperand;
end;

end.

The library module source code now is

library MathDll;

uses
  BaseMath in 'BaseMath.pas',
  MathUnit in 'MathUnit.pas';

function CreateObject: TBaseMathObject;
begin
  Result:= TMathObject.Create;
end;

procedure FreeObject(Obj: TBaseMathObject);
begin
  Obj.Free;
end;

exports
  CreateObject, FreeObject;

{$R *.res}

begin
end.

The executable module source code is

program MathTest;

{$APPTYPE CONSOLE}

uses
  BaseMath in 'BaseMath.pas';

function CreateObject: TBaseMathObject; external 'MathDll.dll';
procedure FreeObject(Obj: TBaseMathObject); external 'MathDll.dll';

var
  MathObj: TBaseMathObject;

begin
  MathObj:= CreateObject;
  MathObj.Operand:= 2;
  Writeln('Square = ', MathObj.Square:3:2, '; Cube = ', MathObj.Cube:3:2);
  FreeObject(MathObj);
  Write('Press ''Enter'' key ... ');
  Readln;
end.

We can see that MathTest project does not contain MathUnit.pas unit, and is not dependent on TMathObject implementation; in fact MathTest project does not know that TMathObject class even exist. We can change TMathObject implementation in dll module as much as we want provided that we keep TBaseMathObject intact, inherit TMathObject from TBaseMathObject and override TBaseMathObject‘s virtual abstract methods.
We implemented a general concept of interface in the form of pure abstract class. Pure abstract classes are a way how interfaces are implemented in C++ . This approach has a limited value in Delphi because Delphi does not support multiple inheritance, and a Delphi class can have only one contract in the form of base abstract class. Another problem is a limited use of ‘is’ and ‘as’ operators for an object created in a different program module:

program IsTest;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  BaseMath in 'BaseMath.pas';

function CreateObject: TBaseMathObject; external 'MathDll.dll';
procedure FreeObject(Obj: TBaseMathObject); external 'MathDll.dll';

var
  MathObj: TBaseMathObject;

procedure TestObj(Obj: TObject);
begin
  try
    Assert(Obj is TBaseMathObject);  // fails
  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;
end;

procedure TestObj2(Obj: TBaseMathObject);
begin
  try
    Assert(Obj is TBaseMathObject);  // success
  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;
end;

begin
  MathObj:= CreateObject;
  TestObj(MathObj);
  TestObj2(MathObj);
  FreeObject(MathObj);
  Write('Press ''Enter'' key ... ');
  Readln;
end.

Here is a brief explanation why the first assertion fails while the second assertion succeeds. Delphi class can be identified by its name or by its VMT. Even if a class does not define any virtual method and VMT itself is empty a pointer to class VMT is still valid. For the TBaseMathObject class we have a single name and two VMT’s, one in .exe module and one in .dll module. That may cause strange behavior, as shown in the above example.
Starting from version 3 Delphi introduces a concept of interface that is different from a pure abstract class and solves the problems with object’s export by using interface references instead of object references:

unit BaseMath;

interface

type
  IBaseMath = interface
  ['{92E9AFF4-25B7-41BD-9EB6-557D12F98BE6}']
    function GetOperand: Double;
    procedure SetOperand(const Value: Double);
    function Square: Double;
    function Cube: Double;
    property Operand: Double read GetOperand write SetOperand;
  end;

implementation

end.

There is no need to inherit TMathObject class from a given base class now; we can inherit TMathObject class from any class we like. Since all Delphi interfaces are descendants of IUnknown (also nicknamed as IInterface in Delphi) we should also implement the methods of IUnknown interface in TMathObject class. Delphi provides a helper TInterfacedObject class that already implements the methods of IUnknown and can be used as TMathObject ancestor:

unit MathUnit;

interface

uses BaseMath;

type
  TMathObject = class(TInterfacedObject, IBaseMath)
  private
    FOperand: Double;
  protected
    function GetOperand: Double;
    procedure SetOperand(const Value: Double);
  public
    function Square: Double;
    function Cube: Double;
  end;

implementation

function TMathObject.GetOperand: Double;
begin
  Result:= FOperand;
end;

procedure TMathObject.SetOperand(const Value: Double);
begin
  FOperand:= Value;
end;

function TMathObject.Square: Double;
begin
  Result:= Sqr(FOperand);
end;

function TMathObject.Cube: Double;
begin
  Result:= Sqr(FOperand) * FOperand;
end;

end.

There is no need for FreeObject procedure now. The FreeObject procedure was introduced in the previous examples to enforce that a TMathObject instance is destroyed in the same program module where it was created (i.e. in .dll module). It is always a good rule of thumb that the one who creates an object is the one who destroys it. But now there is no need to enforce it – if we use interface references object instances are automatically destroyed in the same program module where they were created.

library MathDll;

uses
  BaseMath in 'BaseMath.pas',
  MathUnit in 'MathUnit.pas';

function CreateObject: IBaseMath;
begin
  Result:= TMathObject.Create;
end;

exports
  CreateObject;

{$R *.res}

begin
end.

In the next example a TMathObject object instance is destroyed by assigning nil value to MathObj interface reference. In most cases there is no need for doing it because an object is destroyed automatically when all interface references goes out of scope. In the following code the MathObj interface reference is a global variable and never goes out of scope, so assigning it to nil explicitly makes sense:

program MathTest;

{$APPTYPE CONSOLE}

uses
  BaseMath in 'BaseMath.pas';

function CreateObject: IBaseMath; external 'MathDll.dll';

var
  MathObj: IBaseMath;

begin
  MathObj:= CreateObject;
  MathObj.Operand:= 2;
  Writeln('Square = ', MathObj.Square:3:2, '; Cube = ', MathObj.Cube:3:2);
  MathObj:= nil;
  Write('Press ''Enter'' key ... ');
  Readln;
end.

25 thoughts on “Why we need interfaces in Delphi.

  1. Interfaces are indeed the door to code opening.
    Use of interfaces instead of instances if indeed the mandatory step to implement a true SOLID OOP design.
    See e.g. http://blog.synopse.info/post/2011/11/27/SOLID-design-principles
    For instance, asking for an interface and retrieving an implementation class is a very powerfull pattern.
    I’m about to add interface-based SOA to our Client-Server framework, in order to implement Domain-Driven architecture in Delphi.
    So your article is a first step into Dependency Injection pattern.

  2. Main structural limitation of interfaces in Delphi is their memory management.

    They’re hard-compiled to be reference-counted, but reference-counting is problematic as it only works on trees, not on graphs, so that’s worked around in some classes (like TComponent) by having void reference-counting implementations and having weak references (ie. potential leaks and dangling interfaces). Also the void refcounting implementations are still called by the compiler, so you always pay a performance penalty price when using interfaces (not just the call, but also the implicit exception frames and their consequence on optimizations the compiler can no longer perform).

    Interfaces are a great design tool when garbage-collected, but in Delphi they’re just reference-counted, and when used outside of pure trees, they usually turns of in a whole lot of messy code that looks safe and clean, but is neither.

    • Whenever you use a plain Delphi string in your code, you’ll have this implicit try…finally block, like for every reference-counted variable. So IMHO this is not a real performance penalty price when using interfaces, in comparison to real application bottlenecks (like memory allocation or copy). Interface calls are very well implemented in Delphi (they use a VMT). But a perhaps more real performance bottleneck could be this VMT – every class instance will generate a proper VMT at creation in TObject.InitInstance. So if your class implements a lot of interfaces methods, its creation will be a little bit slower, even if you do not use these interfaces. I still do not understand why this VMT table is created for each instance, whereas it may have been initialized at the class level. If you have any idea…
      Garbage-collectors have also their weaknesses. Even Apple recommends using reference-count instead – see http://developer.apple.com/library/ios/#releasenotes/ObjectiveC/RN-TransitioningToARC/_index.html
      AFAIK this ARC pattern is just like the one used in Delphi for Interfaces (and string, dynamic arrays and variants), with some additional ownership pattern (like TComponent).
      Can you give some sample code of Delphi interface-based “messy code” which leaks memory?

      • @Serg You’re right. I made a confusion between IMT and GUID referencing. TObject.InitInstance does initialize GUID-based interfaces, one entry per GUID, in the class memory instance. So the performance issue is much less than I expected: one entry per implemented GUID, not one per method. I think this copy into the instance is for faster GUID access – am I right? Perhaps a deprecated trick with nowadays CPUs. Thanks for the article link, in all cases.

      • @A. Bouchez: Class instance contains pointers to interface vtables, no more than 1 pointer per each interface. Probably even less if interface inheritance is used – I never investigated so deep. TObject.InitInstance initializes these pointers using class metadata. IMO, the purpose is not fast GUID access, but fast interface method calls (no GUID is used to call interface methods, just a short stub code that converts interface reference into object reference). Remember also about COM-compatibility of Delphi interfaces, it is not an easy task to propose a good alternative implementation of interfaces.

      • String are a very different problem, they can’t cross-reference themselves, and so reference counting them provides a correct solution memory-management-wise, so the cost is justifiable.

        For interfaces, that’s not the case, the reference-counting is insufficient as a form of memory-management, hence the need for weak reference and void implementations, which still end up costing time even when they are doing nothing.

        If you don’t want to see performance issue with interfaces, you need to be careful: only pass them as “const” parameters, don’t have functions or methods returning interfaces.

        The InitInstance initialization is a major waste, it could be handled by the compiler, this was QC’ed way back in the early days of interface support in Delphi.

        As for Apple’s ARC, well, it’s intended to solve an objective-C shortcoming (of manually having to addRef & Release), and doesn’t provide an alternative to GC, as they state in the link you provided; as it has to be since reference-counting doesn’t handle graphs.
        In the introduction they diss pointers as involving a risk of leaks and dangling references, and some paragraphs further they introduce weak references, which are a new name for the the same thing, see “ARC Enforces New Rules” in the link your provided and then “ARC Introduces New Lifetime Qualifiers”.

      • @Eric Thanks for your input.
        I just found out the potential circular reference issue with the current implementation of interfaces within Delphi. I did hear from it some years ago, but since I did not rely on interfaces in my software, I forgot about it.
        I’ve written a blog article to emphasize this at http://blog.synopse.info/post/2011/12/08/Avoiding-Garbage-Collector%3A-Delphi-and-Apple-on-the-same-side
        About performance, it seems not to be the main Embarcadero goal nowadays. It sounds like if the current implementation fit their expectations. I would hardly see them refresh the RTL implementation – only to add some “pure pascal” versions, like they did for the x64 target. Just look at the IntToStr() function implementation, and you’ll find out some slow code. Or the new TMonitor implementation…
        As far as I understood the current implementation problem of interface within Delphi (and FPC), simple types like our reference-counted Delphi variables solve the circular reference issue by providing a copy-on-write behavior. But the interface kind of variable, in its current state, may suffer from this issue.
        Since I want to use interface everywhere in our next version of mORMot (to implement a true Domain-Driven architecture – including SOLID principles), some strict rules may be defined in its usage, not to suffer from similar issues. To my understanding, as soon as you use interfaces in the internal scope of methods (i.e. stack-allocated), you may never suffer for circular reference.
        Additional investigation is certainly needed.
        How does DWS implement interfaces? Did you include some pattern to reduce interface risk? Or do you rely on the internal GC included in your DWS runtime or in the JavaScript engine?
        If you have any idea, your feedback is welcome!

      • DWScript uses both reference counting and a GC, ref counted interfaces are used to provide fast cleanup in trivial cases or when the script is written to manually detach all cross-references, and the GC is there to handle the cleanups (in case of script interruption, script memory leaks, object graphs and cycles…). For more details see:

        http://delphitools.info/2011/03/21/dwscript-objects-memory-model/

        I’ve been looking towards expanding the GC support, as long as things stay script-side, this would be simple, but since the script sooner or later interacts with delphi-side user code, things become far more intricate since Delphi and the RTL just aren’t made to work with a GC (or even refcounting, cf. TComponent). So things would be clunky from the delphi-side.

        The issue of cycles can appear as soon as you have two objects referencing each other via interfaces, that’s the trivial case, and can appear in long cross-referencing cycles too, which are hard to protect against (the only clue there is one is when you start leaking memory or face random memory corruption from dangling pointers…).
        There is really no simple way to be safe from them, it’s just way too easy to get them whenever you use interfaces, even if you’re very strict in your coding practices. FWIW Borland back in the day chose to turn refcounting off for the VCL, which is telling.

  3. I have been struggling with the same question for a long time. However, after reading your article and many other, I am not seeing a clear conclusion as to why do we need interfaces.
    We have been basing most of our design on abstract classes, and while the implementation between abstract classes and interfaces is different, I fail to see the advantages of interfaces.
    The reference counting in my view is not a benefit, similar to a language with garbage collection. I believe it encourages sloppy coding.
    The multiple inheritance available with interfaces could be a benefit if your design uses it. However, we have been developing in Delphi for a number of years, and managed to live with the single inheritance just fine.

    This I miss some crucial point?

    • About the potential benefits of using interfaces instead of class instances, Take a look at the SOLID principles.
      It may be used e.g. in a Domain-Driven design.
      Using a Factory, you can get interfaces you need for your purpose, depending on the context you will use them.
      Just some points when this design can make a difference:
      – In a SOA world: Client-Server use (an Interface on the client side is just a wrapper running the real instance remotely on the server);
      – In Test-Driven model: interfaces are very good to use mocks or stubs instead of plain instances – this will allow to test advanced features without a real database.
      Of course, you can achieve a similar feature using abstract classes with a custom implementation.
      But you’ll certainly break the Interface Segregation principle, therefore you’ll loose modularity, and with RTTI such interfaces can be implemented on the fly without any coding.

      • I recently designed a Delphi plugin system and originally used abstract classes as part of the design. Each plugin provides a distinct set of services so that there is no common API other than some basic information each plugin provides and the host API itself. A plugin can request the API of a particular plugin (eg a graphing window, numeric capabilities) and so long as the plugin has the abstract class is can cast the TObject from the plugin it is interested in to the appropriate class. Now is it possible of course for the wrong cast to be made with resulting problems.

        A couple of week ago I switched over to interfaces and the only advantage I have so far is that the virtual; stdcall; abstract qualifiers are now missing from each plugin API which make them easier to read. The use of interfaces has however has meant a very slight increase in the amount of code I write. Thus instead of directly casting a TObject retrieved from a plugin to the appropriate abstract class I now have to use a two liner involving the method “supports to do the same things”. So other than cleaner looking code I’ve not seen a great advantage. Perhaps I am not familiar enough with the idea of interfaces or the application I have isn’t suitable. I keep researching and articles such as this are very useful so that I might one day see the light and get better use from interfaces.

      • @Herbert Interface Segregation principle is just a good reason of using interfaces.
        I prefer using plain Delphi objects for storing data, but interfaces are a very good way for handling Services.
        Just take a look at the Domain-Driven design approach and implementation.

    • The most crucial point that you are missing is that interfaces are *orthogonal* to class inheritance. Classes implementing a certain interface do not have to be descendants of one base class, as is the case with class inheritance and abstract classes.

      Any class can be made to implement an interface, and any code using that interface will be able to use all classes that implement it, no matter in which class hierarchy they are. Abstract classes are the base for class hierarchies.

      FWIW, how they work is explained here: http://rvelthuis.de/articles/articles-pointers.html#interfaces

      • Over the weekend I did a lot more experimenting and now I am clearer on the differences especially in relation to your comment which I think hits the nail on the head. I think too often writers over emphasize the contract nature of interfaces and the fact that classes and interfaces are orthogonal is lost.

  4. Does the first Assert
    procedure TestObj(Obj: TObject);
    Assert(Obj is TBaseMathObject);
    fail because of different exe/dll class info location of TBaseMathObject only
    and the second Assert
    procedure TestObj2(Obj: TBaseMathObject);
    Assert(Obj is TBaseMathObject);
    pass because the parameter is implicitly casted to TBaseMathObject in exe?

    • Yes. The first ‘Assert’ fails because ‘Obj’ instance is created in .dll module and its VMT pointer references .dll’s VMT. ‘Assert’ itself is called from .exe module and expects a pointer to .exe’s VMT. The second ‘Assert’ does not generate runtime VMT pointer check code.

  5. The interfaced demo works fine, but when I try to load/unload the DLL dinamically, an access violation is raised at the end of the program in the System unit at the _IntfClear function.

    program MathTest;

    {$APPTYPE CONSOLE}

    uses
    Windows,
    BaseMath in ‘BaseMath.pas’;

    //function CreateObject: IBaseMath; external ‘MathDll.dll’;

    type

    TCreateObject = function: IBaseMath; stdcall;

    var

    CreateObject: TCreateObject;
    MathObj: IBaseMath;
    Dll: THandle;

    begin
    Dll := LoadLibrary(‘MathDll.dll’);
    CreateObject := GetProcAddress(Dll, ‘CreateObject’);

    MathObj:= CreateObject;
    MathObj.Operand:= 2;
    Writeln(‘Square = ‘, MathObj.Square:3:2, ‘; Cube = ‘, MathObj.Cube:3:2);
    MathObj:= nil;

    FreeLibrary(Dll);

    Write(‘Press ”Enter” key … ‘);
    Readln;
    // Access Violation is raised here
    end.

  6. Pingback: Why we need interfaces? [closed] | PHP Developer Resource

  7. Great articles. Great Approach of explanation. I read a lot about interfaces, but this articles make you understand EXACTLY what is an Interface. The three examples is the best way to progressively move from one concept to the other. Thank you very much for your efforts.

Leave a comment