Skip to content

Incorrect priority of overloading operator :=

This problem can be seen by comparing the behavior of casting to TValue (Rtti) with Delphi. Everything works fine if we just use function overloads.

program project1;

{$IFDEF FPC}
{$mode objfpc}{$H+}
{$ELSE}
{$APPTYPE CONSOLE}
{$ENDIF}

uses
  {$IFDEF FPC}
  {$IFDEF UNIX}
  cthreads,
  {$ENDIF}
  {$ENDIF}
  {$IFnDEF FPC}System.{$ENDIF}SysUtils,
  {$IFnDEF FPC}System.{$ENDIF}Rtti;

type
  ITestInterface = interface
    ['{12345678-1234-1234-1234-123456789012}']
    procedure DoSomething;
  end;

  TTestClass = class(TInterfacedObject, ITestInterface)
  public
    procedure DoSomething;
  end;

procedure TTestClass.DoSomething;
begin
  Writeln('TTestClass.DoSomething called');
end;

procedure TestType(arg: IUnknown); overload;
begin
  Writeln('Argument of type IUnknown received in overload 1');
end;

procedure TestType(arg: Pointer); overload;
begin
  Writeln('Argument of type Pointer received in overload 2');
end;

procedure TestType(arg: TObject); overload;
begin
  Writeln('Argument of type TObject received in overload 3');
end;

var
  obj: TTestClass;
  tval: TValue;
begin
  try
    obj := TTestClass.Create;
    try
      TestType(obj); // TObject anywhere
    finally
      obj.Free;
    end;

    tval := obj;
    Writeln(tval.ToString);
    {
      Delphi: (TTestClass @ 0342BDB8)
      FPC: (pointer @ 0000000001614170)
        OR
           (interface @ 00000000015F4118)
           (if there is no overloading of the := operator for Pointer at TValue)
    }

    Readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

It is clear that the problem will not occur on Delphi, because there is a single overloading of the Implicit operator to cast objects to TValue. But still, it would be shortsighted to just remove the “unnecessary” overloads and solve the problem, because FPC is adamant that priorities are like that:

  1. Pointer
  2. IUnknown
  3. TObject

But at least the overloads in TValue are arranged in such a way that it should count:

  1. TObject
  2. Pointer
  3. IUnknown
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information