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.

Advertisements