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:
- Pointer
- IUnknown
- TObject
But at least the overloads in TValue are arranged in such a way that it should count:
- TObject
- Pointer
- IUnknown