On the “out” parameter specifier in Delphi

8

I’ve posted before what the “out” parameter specifier is actually doing in a Delphi code. Now let us consider when the “out” keyword should be used instead of “var”.

There is only one case when the “out” keyword should be used. It is closely related to COM technology support, but it is not really limited to COM. The case is importing a function with a parameter of interface type which violates Delphi contract on reference counting. To illustrate the point consider the following DLL:

library DemoDll;

uses
  SysUtils;

type
  PMyUnknown = ^TMyUnknown;
  TMyUnknown = record
    FVTable: PPointer;
    FRefCount: Integer;
    class function QueryIntf(Inst: Pointer; const IID: TGUID;
                             out Obj): HRESULT; stdcall; static;
    class function AddRef(Inst: PMyUnknown): Integer; stdcall; static;
    class function Release(Inst: PMyUnknown): Integer; stdcall; static;
  end;

const
  VTable: array[0..2] of Pointer = (
    @TMyUnknown.QueryIntf,
    @TMyUnknown.Addref,
    @TMyUnknown.Release);

function ReleaseInstance(Inst: Pointer): Integer;
type
  TVTable = array[0..2] of Pointer;
  PVTable = ^TVTable;
  PPVTable = ^PVTable;

  TRelease = function(Inst: Pointer): Integer; stdcall;

begin
  Result:= TRelease(PPVTable(Inst)^^[2])(Inst);
end;

class function TMyUnknown.QueryIntf(Inst: Pointer; const IID: TGUID;
  out Obj): HRESULT;
begin
  Result:= E_NOINTERFACE;
end;

class function TMyUnknown.Addref(Inst: PMyUnknown): Integer;
begin
  Inc(Inst.FRefCount);
  Result:= Inst.FRefCount;
end;

class function TMyUnknown.Release(Inst: PMyUnknown): Integer;
begin
  Dec(Inst.FRefCount);
  Result:= Inst.FRefCount;
  if Result = 0 then
    FreeMem(Inst);
end;

procedure GetIUnknown1(var Inst: PMyUnknown);
var
  P: PMyUnknown;

begin
  New(P);
  P^.FVTable:= @VTable;
  P^.FRefCount:= 1;
  if Inst <> nil then ReleaseInstance(Inst);
  Inst:= P;
end;

procedure GetIUnknown2(var Inst: PMyUnknown);
begin
  New(Inst);
  Inst^.FVTable:= @VTable;
  Inst^.FRefCount:= 1;
end;

exports
  GetIUnknown1,
  GetIUnknown2;

{$R *.res}

begin
  ReportMemoryLeaksOnShutdown:= True;
end.

The DLL exports 2 procedures which create instances implementing IUnknown. The first procedure (GetIUnknown1) follows Delphi rules on reference counting, the second (GetIUnknown2) does not. To use the procedures in an executable we need an import unit:

unit DemoImport;

interface

procedure GetIUnknown1(var I: IUnknown);
//procedure GetIUnknown2(var I: IUnknown); // memory leak
procedure GetIUnknown2(out I: IUnknown);
//                     ^^^!
implementation

procedure GetIUnknown1(var I: IUnknown); external 'DemoDLL' name 'GetIUnknown1';
//procedure GetIUnknown2(var I: IUnknown); external 'DemoDLL' name 'GetIUnknown2';
procedure GetIUnknown2(out I: IUnknown); external 'DemoDLL' name 'GetIUnknown2';

end.

Note that the second procedure is imported with out parameter specifier; the result of replacing “out” by “var” is a memory leak which can be shown by the test application:

program DemoEXE;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  DemoImport in 'DemoImport.pas';

procedure Test;
var
  I: IUnknown;

begin
  GetIUnknown1(I);
  GetIUnknown2(I);
end;

begin
  Test;
  Readln;
end.

Implementing generic interfaces in Delphi

9

Delphi supports generic interfaces; for example we can declare a generic interface

type
  IChecker<T> = interface
    function Check(const Instance: T): Boolean;
  end;

and use this generic interface as follows:

unit UseDemo;

interface

uses GenChecks;

type
  TDemo<T> = class
  private
    FChecker: IChecker<T>;
  public
    constructor Create(AChecker: IChecker<T>);
    procedure Check(AValue: T);
  end;

implementation

{ TDemo<T> }

procedure TDemo<T>.Check(AValue: T);
begin
  if FChecker.Check(AValue)
    then Writeln('Passed')
    else Writeln('Stopped')
end;

constructor TDemo<T>.Create(AChecker: IChecker<T>);
begin
  FChecker:= AChecker;
end;

end.

To implement the above generic interface IChecker we need a generic class; the straightforward solution is

type
  TChecker<T> = class(TInterfacedObject, IChecker<T>)
    function Check(const Instance: T): Boolean;
  end;

If the IChecker interface can be implemented like that, we need nothing else. The problem with the above implementation is that we are limited to the generic constraints on the type T and can’t use properties of specific types like Integer or string that will finally be substituted for the type T.

A more elastic solution is to introduce an abstract base type and derive the specific implementations from it. Here is a full code example:

program GenericEx1;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  GenChecks in 'GenChecks.pas',
  UseDemo in 'UseDemo.pas';

procedure TestInt;
var
  Demo: TDemo<Integer>;

begin
  Demo:= TDemo<Integer>.Create(TIntChecker.Create(42));
  Demo.Check(0);
  Demo.Check(42);
end;

procedure TestStr;
var
  Demo: TDemo<string>;

begin
  Demo:= TDemo<string>.Create(TStrChecker.Create('trololo'));
  Demo.Check('ololo');
  Demo.Check('olololo');
end;

begin
  TestInt;
  TestStr;
  ReadLn;
end.
unit GenChecks;

interface

type
  IChecker<T> = interface
    function Check(const Instance: T): Boolean;
  end;

type
  TCustomChecker<T> = class(TInterfacedObject, IChecker<T>)
  protected
    FCheckValue: T;
    function Check(const Instance: T): Boolean; virtual; abstract;
  public
    constructor Create(ACheckValue: T);
  end;

  TIntChecker = class(TCustomChecker<Integer>)
  protected
    function Check(const Instance: Integer): Boolean; override;
  end;

  TStrChecker = class(TCustomChecker<string>)
  protected
    function Check(const Instance: string): Boolean; override;
  end;

implementation

{ TCustomChecker<T> }

constructor TCustomChecker<T>.Create(ACheckValue: T);
begin
  FCheckValue:= ACheckValue;
end;

{ TIntChecker }

function TIntChecker.Check(const Instance: Integer): Boolean;
begin
  Result:= Instance = FCheckValue;
end;

{ TStrChecker }

function TStrChecker.Check(const Instance: string): Boolean;
begin
  Result:= Length(Instance) = Length(FCheckValue);
end;

end.

In the above example each interface reference ICheck references its own class instance; this is necessary because every instance contains a parameter (FCheckValue) set in the constructor. If an implementation does not require such a parameter creating new instances for every interface reference will be an overhead. A better solution is to use a singleton instance.

Here is a full code example for the integer type:

program GenericEx2;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  GenChecks in 'GenChecks.pas',
  UseDemo in 'UseDemo.pas';

procedure TestInt;
var
  Demo: TDemo<Integer>;

begin
  Demo:= TDemo<Integer>.Create(TIntChecker.Ordinal);
  Demo.Check(0);
  Demo.Check(42);
end;

begin
  TestInt;
  ReadLn;
end.
unit GenChecks;

interface

uses Generics.Defaults;

type
  IChecker<T> = interface
    function Check(const Instance: T): Boolean;
  end;

  TCustomChecker<T> = class(TSingletonImplementation, IChecker<T>)
  protected
    function Check(const Instance: T): Boolean; virtual; abstract;
  end;

  TIntChecker = class(TCustomChecker<Integer>)
  private
    class var
      FOrdinal: TCustomChecker<Integer>;
  public
    class function Ordinal: TIntChecker;
  end;

implementation

type
  TOrdinalIntChecker = class(TIntChecker)
  public
    function Check(const Instance: Integer): Boolean; override;
  end;

{ TOrdinalIntChecker }

function TOrdinalIntChecker.Check(const Instance: Integer): Boolean;
begin
  Result:= Instance = 42;
end;

{ TIntChecker }

class function TIntChecker.Ordinal: TIntChecker;
begin
  if FOrdinal = nil then
    FOrdinal := TOrdinalIntChecker.Create;
  Result := TIntChecker(FOrdinal);
end;

end.

Goodbye, TObject

7

I’m not using TObject in my Delphi code anymore. Sure I use the core classes like TStream derived from TObject but I don’t derive my own classes from TObject or descendant classes. I am using a different OOP paradigm instead.
It all started when I was looking for a simple-to-use and efficient BigInteger type in Delphi and the solution seems absolutely evident now when I am looking back at it:

type
  IBigNumber = interface
/*
  interface methods
*/
  end;

type
  BigInteger = record
  private
    FNumber: IBigNumber;
  public
/*
  public methods and overloaded operators
*/
  end;

The BigInteger type is an interface reference wrapped in the advanced record; SizeOf(BigInteger) = SizeOf(Pointer).

Let us generalize the above idea. Instead of

type
  TMyObject = class
/*
..
*/
  end;

we use the alternative:

type
  IMyObject = interface
/*
..
*/
  end;

  TMyObject = record
  private
    FMyObject: IMyObject;
  public
/*
..
*/
  end;

You can see that the alternative requires more code typing. What we obtain for more work?

  • IMyObject can be implemented in DLL and used with different programming languages;
  • We obtain automatic memory management based on reference counting;
  • Automatic memory management makes possible fluent coding;
  • We can overload operators in TMyObject;
  • We get rid of all TObject overhead.

You may ask what about inheritance and polymorphism (late binding)? These are moved from classes (TMyObject) to interfaces (IMyObject), and the move makes coding more elastic. We now have separate inheritance of interfaces and implementations, and interfaces are always polymorphic (late bound).
You can notice that interfaces in Delphi are implemented using classes derived from TInterfacedObject but as I posted before this is not necessary – interfaces can be implemented in a more compact and efficient way.

And this closes the ring; TObject is not needed.

Interfaces without objects

19

Delphi interfaces are usually implemented by objects, but that is not necessary. Like you can implement a COM interface in pure C, you can implement a Delphi interface (which follows COM specifications in general) in pure Pascal without using objects.

To demonstrate the technique let us consider the following example:

unit CalcIntf;

interface

type
  ICalculator = interface
    procedure Clear;
    procedure Add(AValue: Integer);
    procedure Sub(AValue: Integer);
    function GetAccumulator: Integer;
  end;

implementation

end.

Here is a standard Delphi implementation of ICalculator interface by TInterfacedObject descendant:

unit CalcObjects;

interface

uses CalcIntf;

function GetCalculator: ICalculator;

implementation

type
  TCalcObj = class(TInterfacedObject, ICalculator)
    FAccumulator: Integer;
    procedure Clear;
    procedure Add(AValue: Integer);
    procedure Sub(AValue: Integer);
    function GetAccumulator: Integer;
  end;

procedure TCalcObj.Clear;
begin
  FAccumulator:= 0;
end;

function TCalcObj.GetAccumulator: Integer;
begin
  Result:= FAccumulator;
end;

procedure TCalcObj.Add(AValue: Integer);
begin
  Inc(FAccumulator, AValue);
end;

procedure TCalcObj.Sub(AValue: Integer);
begin
  Dec(FAccumulator, AValue);
end;

function GetCalculator: ICalculator;
begin
  Result:= TCalcObj.Create;
end;

end.

Our task is to implement ICalculator interface using a record instance instead of an object instance. I have described the internals of Delphi interfaces before. In the above example the GetCalculator function returns a pointer to the hidden vtable field of TCalcObj instance. If we use a record instead of an object we should declare this field explicitely; if we declare this field first we also get rid of stub code that converts a pointer to vtable field of an instance to a pointer to an instance itself and make interface functions’ calls faster:

type
  PCalcData = ^TCalcData;
  TCalcData = record
    FVTable: Pointer;
    FRefCount: Integer;
    FAccumulator: Integer;
  end;

Now the GetCalculator function should return a pointer to FVTable field of a record; since FVTable field is the first field of the TCalcData record, it is a pointer to record instance itself. A working solution is presented below; I used static class methods of an advanced record instead of ordinary functions only to scope the functions’ names:

unit CalcRecords;

interface

uses CalcIntf;

function GetCalculator: ICalculator;

implementation

type
  PCalcData = ^TCalcData;
  TCalcData = record
    FVTable: Pointer;
    FRefCount: Integer;
    FAccumulator: Integer;
  end;

  TCalcRec = record
    Data: PCalcData;
    class function QueryIntf(Inst: PCalcData; const IID: TGUID;
                             out Obj): HResult; stdcall; static;
    class function Addref(Inst: PCalcData): Integer; stdcall; static;
    class function Release(Inst: PCalcData): Integer; stdcall; static;
    class procedure Clear(Inst: PCalcData); static;
    class procedure Add(Inst: PCalcData; AValue: Integer); static;
    class procedure Sub(Inst: PCalcData; AValue: Integer); static;
    class function GetAccumulator(Inst: PCalcData): Integer; static;
  end;

function InterlockedAdd(var Value: Integer; Increment: Integer): Integer;
asm
      MOV   ECX,EAX
      MOV   EAX,EDX
 LOCK XADD  [ECX],EAX
      ADD   EAX,EDX
end;

function InterlockedIncrement(var Value: Integer): Integer;
asm
      MOV   EDX,1
      JMP   InterlockedAdd
end;

function InterlockedDecrement(var Value: Integer): Integer;
asm
      MOV   EDX,-1
      JMP   InterlockedAdd
end;

class function TCalcRec.QueryIntf(Inst: PCalcData; const IID: TGUID; out Obj): HResult;
begin
  Result:= E_NOINTERFACE;
end;

class function TCalcRec.Addref(Inst: PCalcData): Integer;
begin
  Result:= InterlockedIncrement(Inst^.FRefCount);
end;

class function TCalcRec.Release(Inst: PCalcData): Integer;
begin
  Result:= InterlockedDecrement(Inst^.FRefCount);
  if Result = 0 then
    Dispose(Inst);
end;

class procedure TCalcRec.Clear(Inst: PCalcData);
begin
  Inst^.FAccumulator:= 0;
end;

class function TCalcRec.GetAccumulator(Inst: PCalcData): Integer;
begin
  Result:= Inst^.FAccumulator;
end;

class procedure TCalcRec.Add(Inst: PCalcData; AValue: Integer);
begin
  Inc(Inst^.FAccumulator, AValue);
end;

class procedure TCalcRec.Sub(Inst: PCalcData; AValue: Integer);
begin
  Dec(Inst^.FAccumulator, AValue);
end;

const
  CalcVTable: array[0..6] of Pointer =
  (
    @TCalcRec.QueryIntf,
    @TCalcRec.Addref,
    @TCalcRec.Release,
    @TCalcRec.Clear,
    @TCalcRec.Add,
    @TCalcRec.Sub,
    @TCalcRec.GetAccumulator
  );

function GetCalculator: ICalculator;
var
  P: PCalcData;

begin
  New(P);
  P^.FVTable:= @CalcVTable;
  P^.FRefCount:= 0;
  P^.FAccumulator:= 0;
  Result:= ICalculator(P);
end;

end.

Here is a simple test code:

uses CalcIntf, CalcObjects, CalcRecords;

procedure TForm1.Button1Click(Sender: TObject);
var
  ICalc: ICalculator;

begin
  ICalc:= CalcObjects.GetCalculator;
  ICalc.Add(42);
  ShowMessage(IntToStr(ICalc.GetAccumulator));
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  ICalc: ICalculator;

begin
  ICalc:= CalcRecords.GetCalculator;
  ICalc.Add(42);
  ShowMessage(IntToStr(ICalc.GetAccumulator));
end;

Why we need interfaces in Delphi.

25

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.

TInteger

2

Since the introduction of operator overloading in Delphi one can easily define custom data types that support arithmetic operations. For example it is quite easy to implement arithmetic of complex numbers like this:

type
  PComplex = ^TComplex;
  TComplex = record
    Re, Im: Extended;

    class operator Implicit(const A: Extended): TComplex;

    class operator Add(const A, B: TComplex): TksComplex;
    class operator Subtract(const A, B: TComplex): TComplex;
    class operator Multiply(const A, B: TComplex): TComplex;
{...}

Note that TComplex is a static type with fixed data size (Re, Im fields) and is normally allocated on stack. The problems arise when you need to implement arithmetic on dynamic data allocated on heap.
If you are about to implement big integer (TInteger) arithmetic you have two alternatives.
First, you can stick to static data types; that means that you should limit maximum number value in the implementation.
The second alternative is to use dynamic type to allocate the numbers, so there is no need to introduce artificial limits on maximum number value.

The first approach is obvious, the second is more interesting.
You can’t use GetMem/FreeMem to allocate/deallocate the numbers on heap because memory deallocation should be performed automatically by the compiler, and you just cannot instruct the compiler to call FreeMem for temporary TInteger value while evaluating arithmetic expression like

A:= (B + C) * D;

Consequently, the dynamic type to hold the number data should be lifetime-managed type – and the dynamic array seems to be the most probable candidate:

type
  TInteger = record
  private
    FData: array of LongWord;
{...}

The above implementation forbids “in-place” operations on TInteger variables – the reason is a side effect of TInteger assignment. Dynamic arrays do not support copy-on-write, so the following assertion will fail:

var
  A, B: TInteger;

begin
  A:= 1;
  B:= A;
  Inc(A);
  Assert(B=1);
end;

After B:= A both A.FData and B.FData reference the same data, so that after Inc(A) we have B = 2.

Now we have 3 alternatives:

  • we can avoid completely the in-place operations on TInteger;
  • we can use undocumented format of dynamic array to implement TInteger “copy-on-write” by hacking dynamic array’s reference count before calling in-place operations;
  • we can use interfaces.

(Well, there are lifetime-managed data types in Delphi that support “copy-on-write” semantic – strings, but they can’t help us since we need some low-level hacking to manipulate the binary data in string format and “copy-on-write” will not work as we need).

Let us try the following:

type
  PIntegerData = ^TIntegerData;
  TIntegerData = record
    Size: LongInt;   // number of allocated longwords in Data
    Data: array[0..0] of LongWord;
  end;

  IInteger = interface
    function GetData: PIntegerData;
    function GetRefCount: Integer;
  end;

  TIntegerObject = class(TInterfacedObject, IInteger)
  private
    FData: PIntegerData;
  public
    constructor Create(Limbs: Integer);
    destructor Destroy; override;
    function GetData: PIntegerData;
    function GetRefCount: Integer;
  end;

  TInteger = record
  private
    FInteger: IInteger;
{..}

The implementation based on interfaces is the most “correct”. It does not use any dirty hacking or undocumented features to get reference count and implement “copy-on-write”. The bad thing is that the above implementation has the worst performance. For example, to allocate a single TInteger value you need to allocate two memory blocks on heap – first for a TIntegerObject and second for TIntegerData referenced by the TIntegerObject.

All in all, a TInteger implementation based on dynamic arrays (with or without refcount hacking) looks most optimal today.

Delphi interfaces without reference counting

13

Any interface in Delphi inherits from IInterface (which is a nickname for IUnknown). It is nice for reference-counted interfaces, but sometimes we do not need reference counting at all. Consider the following example:

unit IValues;

interface

type
  IValue = interface(IInterface)
    function GetValue: Integer;
  end;

function GetIValue: IValue;

implementation

type
  TValueObject = class(TObject, IValue)
  protected
    FValue: Integer;
    function GetValue: Integer;
  public
    constructor Create(AValue: Integer);
  end;

var
  FValueObject: TValueObject;

function GetIValue: IValue;
begin
  Result:= FValueObject;
end;

constructor TValueObject.Create(AValue: Integer);
begin
  FValue:= AValue;
end;

function TValueObject.GetValue: Integer;
begin
  Result:= FValue;
end;

initialization
  FValueObject:= TValueObject.Create(11);

finalization
  FValueObject.Free;

end.

The above code does not compile because TValueObject does not implement IUnknown. A workaround is to implement stub methods for IUnknown:

type
  TValueObject = class(TObject, IValue)
  protected
    FValue: Integer;
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
    function GetValue: Integer;
  public
    constructor Create(AValue: Integer);
  end;
 
function TValueObject.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
  if GetInterface(IID, Obj) then
    Result:= S_OK
  else
    Result:= E_NOINTERFACE;
end;

function TValueObject._AddRef: Integer;
begin
  Result:= -1;
end;

function TValueObject._Release: Integer;
begin
  Result:= -1;
end;

You can find the same code in VCL sources (TCustomVariantType class from Variants.pas unit).

Now, why should I implement IUnknown in my code if I don’t need it at all?

The above implementation of IUnknown looks like a standard implementation for non-reference-counted interfaces in Delphi. Why not to include it into System.pas and apply compiler magic to make the code in the first example compilable and legitimate? The implementation does not use additional object fields (TInterfacedObject implementation requires additional FRefCount field), so it seems like all that is required from the compiler is to insert pointers to the default IUnknown method’s implementations into the interface tables of any class that does not implement or inherit these methods can be implemented directly in TObject. It will save the programmer from writing a useless duplicate code. The compiler may also issue a warning for the safety reasons, if necessary.